Always include platform immodules
authorMatthias Clasen <mclasen@redhat.com>
Fri, 23 Feb 2018 19:59:49 +0000 (14:59 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 25 Feb 2018 02:34:40 +0000 (21:34 -0500)
No need to load these as gio modules, we just include
them in libgtk.

27 files changed:
gtk/gtk-text-input.xml [new file with mode: 0644]
gtk/gtkimcontextbroadway.c [new file with mode: 0644]
gtk/gtkimcontextbroadway.h [new file with mode: 0644]
gtk/gtkimcontextime.c [new file with mode: 0644]
gtk/gtkimcontextime.h [new file with mode: 0644]
gtk/gtkimcontextquartz.c [new file with mode: 0644]
gtk/gtkimcontextquartz.h [new file with mode: 0644]
gtk/gtkimcontextwayland.c [new file with mode: 0644]
gtk/gtkimcontextwayland.h [new file with mode: 0644]
gtk/gtkimcontextxim.c [new file with mode: 0644]
gtk/gtkimcontextxim.h [new file with mode: 0644]
gtk/gtkimmodule.c
gtk/imm-extra.h [new file with mode: 0644]
gtk/meson.build
meson.build
meson_options.txt
modules/input/gtk-text-input.xml [deleted file]
modules/input/gtkimcontextime.c [deleted file]
modules/input/gtkimcontextime.h [deleted file]
modules/input/gtkimcontextxim.c [deleted file]
modules/input/gtkimcontextxim.h [deleted file]
modules/input/imbroadway.c [deleted file]
modules/input/imm-extra.h [deleted file]
modules/input/imquartz.c [deleted file]
modules/input/imwayland.c [deleted file]
modules/input/meson.build [deleted file]
modules/meson.build

diff --git a/gtk/gtk-text-input.xml b/gtk/gtk-text-input.xml
new file mode 100644 (file)
index 0000000..a134a19
--- /dev/null
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<protocol name="gtk_text_input">
+  <copyright>
+    Copyright © 2012, 2013 Intel Corporation
+    Copyright © 2015, 2016 Jan Arne Petersen
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <interface name="gtk_text_input" version="1">
+    <description summary="text input">
+      The gtk_text_input interface represents text input and input methods
+      associated with a seat. It provides enter/leave events to follow the
+      text input focus for a seat.
+
+      Requests are used to enable/disable the text-input object and set
+      state information like surrounding and selected text or the content type.
+      The information about the entered text is sent to the text-input object
+      via the pre-edit and commit_string events. Using this interface removes
+      the need for applications to directly process hardware key events and
+      compose text out of them.
+
+      Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
+      have to always point to the first byte of an UTF-8 encoded code point.
+      Lengths are not allowed to contain just a part of an UTF-8 encoded code
+      point.
+
+      Focus moving throughout surfaces will result in the emission of
+      gtk_text_input.enter and gtk_text_input.leave events. The focused
+      surface must perform gtk_text_input.enable and
+      gtk_text_input.disable requests as the keyboard focus moves across
+      editable and non-editable elements of the UI. Those two requests are not
+      expected to be paired with each other, the compositor must be able to
+      handle consecutive series of the same request.
+
+      State is sent by the state requests (set_surrounding_text,
+      set_content_type and set_cursor_rectangle) and a commit request.
+      After an enter event or disable request all state information is
+      invalidated and needs to be resent by the client.
+
+      This protocol defines requests and events necessary for regular clients
+      to communicate with an input method. The gtk_input_method protocol
+      defines the interfaces necessary to implement standalone input methods.
+      If a compositor implements both interfaces, it will be the arbiter of the
+      communication between both.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the wp_text_input">
+       Destroy the wp_text_input object. Also disables all surfaces enabled
+       through this wp_text_input object
+      </description>
+    </request>
+
+    <enum name="enable_flags" bitfield="true">
+      <description summary="enable flags">
+       Content hint is a bitmask to allow to modify the behavior of the text
+       input.
+      </description>
+      <entry name="none" value="0x0" summary="no special behaviour"/>
+      <entry name="can_show_preedit" value="0x1" summary="hints that the UI is capable of showing pre-edit text"/>
+      <entry name="toggle_input_panel" value="0x2" summary="requests toggling input panel (eg. on-screen keyboard)"/>
+    </enum>
+
+    <request name="enable">
+      <description summary="Request text input to be enabled">
+       Requests text input on a surface. The serial provided must be the one
+        received on gtk_text_input.enter.
+      </description>
+      <arg name="serial" type="uint" summary="serial of enter event"/>
+      <arg name="show_input_panel" type="uint" summary="details of the enable request"/>
+    </request>
+
+    <request name="disable">
+      <description summary="Disable text input on a surface">
+       Explicitly disable text input in a surface (typically when there is no
+       focus on any text entry inside the surface).
+      </description>
+    </request>
+
+    <request name="set_surrounding_text">
+      <description summary="sets the surrounding text">
+       Sets the plain surrounding text around the input position. Text is
+       UTF-8 encoded. Cursor is the byte offset within the surrounding text.
+       Anchor is the byte offset of the selection anchor within the
+       surrounding text. If there is no selected text, anchor is the same as
+       cursor.
+
+       Make sure to always send some text before and after the cursor
+       except when the cursor is at the beginning or end of text.
+
+       When there was a configure_surrounding_text event take the
+       before_cursor and after_cursor arguments into account for picking how
+       much surrounding text to send.
+
+       There is a maximum length of wayland messages so text can not be
+       longer than 4000 bytes.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="int"/>
+      <arg name="anchor" type="int"/>
+    </request>
+
+    <enum name="content_hint" bitfield="true">
+      <description summary="content hint">
+       Content hint is a bitmask to allow to modify the behavior of the text
+       input.
+      </description>
+      <entry name="none" value="0x0" summary="no special behaviour"/>
+      <entry name="completion" value="0x1" summary="suggest word completions"/>
+      <entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
+      <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
+      <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
+      <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
+      <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
+      <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
+      <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
+      <entry name="latin" value="0x100" summary="just latin characters should be entered"/>
+      <entry name="multiline" value="0x200" summary="the text input is multiline"/>
+    </enum>
+
+    <enum name="content_purpose">
+      <description summary="content purpose">
+       The content purpose allows to specify the primary purpose of a text
+       input.
+
+       This allows an input method to show special purpose input panels with
+       extra characters or to disallow some characters.
+      </description>
+      <entry name="normal" value="0" summary="default input, allowing all characters"/>
+      <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
+      <entry name="digits" value="2" summary="allow only digits"/>
+      <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
+      <entry name="phone" value="4" summary="input a phone number"/>
+      <entry name="url" value="5" summary="input an URL"/>
+      <entry name="email" value="6" summary="input an email address"/>
+      <entry name="name" value="7" summary="input a name of a person"/>
+      <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/>
+      <entry name="pin" value="9" summary="input is a numeric password (combine with password or sensitive_data hint)"/>
+      <entry name="date" value="10" summary="input a date"/>
+      <entry name="time" value="11" summary="input a time"/>
+      <entry name="datetime" value="12" summary="input a date and time"/>
+      <entry name="terminal" value="13" summary="input for a terminal"/>
+    </enum>
+
+    <request name="set_content_type">
+      <description summary="set content purpose and hint">
+       Sets the content purpose and content hint. While the purpose is the
+       basic purpose of an input field, the hint flags allow to modify some
+       of the behavior.
+
+       When no content type is explicitly set, a normal content purpose with
+       none hint should be assumed.
+      </description>
+      <arg name="hint" type="uint" enum="content_hint"/>
+      <arg name="purpose" type="uint" enum="content_purpose"/>
+    </request>
+
+    <request name="set_cursor_rectangle">
+      <description summary="set cursor position">
+       Sets the cursor outline as a x, y, width, height rectangle in surface
+       local coordinates.
+
+       Allows the compositor to put a window with word suggestions near the
+       cursor.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit state">
+       Allows to atomically send state updates from client. The previous
+       set_surrounding_text, set_content_type and set_cursor_rectangle
+       become effective after this call.
+
+       Serial should be set to the serial from the last wp_text_input.enter
+       event.
+
+       To make sure to not receive outdated input method events after a
+       state update, wl_display_sync() should be called after making this
+       request.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+       Notification that this seat's text-input focus is on a certain surface.
+
+       When the seat has the keyboard capability the text-input focus follows
+       the keyboard focus.
+      </description>
+      <arg name="serial" type="uint" summary="serial"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+       Notification that this seat's text-input focus is no longer on
+       a certain surface. The client should reset any preedit string previously
+       set.
+
+       The leave notification is sent before the enter notification
+       for the new focus.
+
+       When the seat has the keyboard capability the text-input focus follows
+       the keyboard focus.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="preedit_string">
+      <description summary="pre-edit">
+       Notify when a new composing text (pre-edit) should be set around the
+       current cursor position. Any previously set composing text should
+       be removed.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+      <arg name="cursor" type="uint"/>
+    </event>
+
+    <event name="commit_string">
+      <description summary="text commit">
+       Notify when text should be inserted into the editor widget. The text to
+       commit could be either just a single character after a key press or the
+       result of some composing (pre-edit).
+
+       The text argument could be also null if some text is removed (see
+       gtk_text_input.delete_surrounding_text).
+
+       Any previously set composing text should be removed.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+    </event>
+
+    <event name="delete_surrounding_text">
+      <description summary="delete surrounding text">
+       Notify when the text around the current cursor position should be
+       deleted. Before_length and after_length is the length (in bytes) of text
+       before and after the current cursor position (excluding the selection)
+       to delete.
+
+       This event should be handled as part of a following commit_string or
+       preedit_string event.
+      </description>
+      <arg name="before_length" type="uint" summary="length of text before current cursor position"/>
+      <arg name="after_length" type="uint" summary="length of text after current cursor position"/>
+    </event>
+  </interface>
+
+  <interface name="gtk_text_input_manager" version="1">
+    <description summary="text input manager">
+      A factory for text-input objects. This object is a global singleton.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the wp_text_input_manager">
+       Destroy the wp_text_input_manager object.
+      </description>
+    </request>
+
+    <request name="get_text_input">
+      <description summary="create a new text input object">
+       Creates a new text-input object for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="gtk_text_input"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/gtk/gtkimcontextbroadway.c b/gtk/gtkimcontextbroadway.c
new file mode 100644 (file)
index 0000000..e8e459a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * gtkimmodulebroadway
+ * Copyright (C) 2013 Alexander Larsson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * $Id:$
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gtk/gtkimcontextbroadway.h"
+#include "gtk/gtkintl.h"
+#include "gtk/gtkimmodule.h"
+
+#include "gdk/broadway/gdkbroadway.h"
+
+#define GTK_TYPE_IM_CONTEXT_BROADWAY (gtk_im_context_broadway_get_type ())
+#define GTK_IM_CONTEXT_BROADWAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_BROADWAY, GtkIMContextBroadway))
+#define GTK_IM_CONTEXT_BROADWAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_IM_CONTEXT_BROADWAY, GtkIMContextBroadwayClass))
+
+typedef struct _GtkIMContextBroadway
+{
+  GtkIMContextSimple parent;
+  GtkWidget *client_widget;
+} GtkIMContextBroadway;
+
+typedef struct _GtkIMContextBroadwayClass
+{
+  GtkIMContextSimpleClass parent_class;
+} GtkIMContextBroadwayClass;
+
+G_DEFINE_TYPE_WITH_CODE (GtkIMContextBroadway, gtk_im_context_broadway, GTK_TYPE_IM_CONTEXT_SIMPLE,
+                         g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "broadway",
+                                                         10))
+
+static void
+broadway_set_client_widget (GtkIMContext *context, GtkWidget *widget)
+{
+  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
+
+  bw->client_widget = widget;
+}
+
+static void
+broadway_focus_in (GtkIMContext *context)
+{
+  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
+  GdkDisplay *display;
+
+  if (bw->client_widget)
+    {
+      display = gtk_widget_get_display (bw->client_widget);
+      gdk_broadway_display_show_keyboard (GDK_BROADWAY_DISPLAY (display));
+    }
+}
+
+static void
+broadway_focus_out (GtkIMContext *context)
+{
+  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
+  GdkDisplay *display;
+
+  if (bw->client_widget)
+    {
+      display = gtk_widget_get_display (bw->client_widget);
+      gdk_broadway_display_hide_keyboard (GDK_BROADWAY_DISPLAY (display));
+    }
+}
+
+static void
+gtk_im_context_broadway_class_init (GtkIMContextBroadwayClass *class)
+{
+  GtkIMContextClass *klass = GTK_IM_CONTEXT_CLASS (class);
+
+  klass->focus_in = broadway_focus_in;
+  klass->focus_out = broadway_focus_out;
+  klass->set_client_widget = broadway_set_client_widget;
+}
+
+static void
+gtk_im_context_broadway_init (GtkIMContextBroadway *im_context)
+{
+}
diff --git a/gtk/gtkimcontextbroadway.h b/gtk/gtkimcontextbroadway.h
new file mode 100644 (file)
index 0000000..aacf60d
--- /dev/null
@@ -0,0 +1,29 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_IM_CONTEXT_BROADWAY_H__
+#define __GTK_IM_CONTEXT_BROADWAY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+GType gtk_im_context_broadway_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_IM_CONTEXT_BROADWAY_H__ */
diff --git a/gtk/gtkimcontextime.c b/gtk/gtkimcontextime.c
new file mode 100644 (file)
index 0000000..7ba1483
--- /dev/null
@@ -0,0 +1,1191 @@
+/*
+ * gtkimcontextime.c
+ * Copyright (C) 2003 Takuro Ashie
+ * Copyright (C) 2003-2004 Kazuki IWAMOTO
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ *  Please see the following site for the detail of Windows IME API.
+ *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/appendix/hh/appendix/imeimes2_35ph.asp
+ */
+
+#ifdef GTK_DISABLE_DEPRECATED
+#undef GTK_DISABLE_DEPRECATED
+#endif
+
+#include "gtkimcontextime.h"
+
+#include "imm-extra.h"
+
+#include "gdk/gdkkeysyms.h"
+#include "gdk/win32/gdkwin32.h"
+#include "gdk/gdkkeysyms.h"
+
+#include <pango/pango.h>
+
+/* avoid warning */
+#ifdef STRICT
+# undef STRICT
+# include <pango/pangowin32.h>
+# ifndef STRICT
+#   define STRICT 1
+# endif
+#else /* STRICT */
+#   include <pango/pangowin32.h>
+#endif /* STRICT */
+
+/* #define BUFSIZE 4096 */
+
+#define IS_DEAD_KEY(k) \
+    ((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
+
+#define FREE_PREEDIT_BUFFER(ctx) \
+{                                \
+  g_free((ctx)->priv->comp_str); \
+  g_free((ctx)->priv->read_str); \
+  (ctx)->priv->comp_str = NULL;  \
+  (ctx)->priv->read_str = NULL;  \
+  (ctx)->priv->comp_str_len = 0; \
+  (ctx)->priv->read_str_len = 0; \
+}
+
+
+struct _GtkIMContextIMEPrivate
+{
+  /* save IME context when the client window is focused out */
+  DWORD conversion_mode;
+  DWORD sentence_mode;
+
+  LPVOID comp_str;
+  DWORD comp_str_len;
+  LPVOID read_str;
+  DWORD read_str_len;
+
+  guint32 dead_key_keyval;
+};
+
+
+/* GObject class methods */
+static void gtk_im_context_ime_class_init (GtkIMContextIMEClass *class);
+static void gtk_im_context_ime_init       (GtkIMContextIME      *context_ime);
+static void gtk_im_context_ime_dispose    (GObject              *obj);
+static void gtk_im_context_ime_finalize   (GObject              *obj);
+
+static void gtk_im_context_ime_set_property (GObject      *object,
+                                             guint         prop_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec);
+static void gtk_im_context_ime_get_property (GObject      *object,
+                                             guint         prop_id,
+                                             GValue       *value,
+                                             GParamSpec   *pspec);
+
+/* GtkIMContext's virtual functions */
+static void gtk_im_context_ime_set_client_widget   (GtkIMContext *context,
+                                                    GtkWidget    *widget);
+static gboolean gtk_im_context_ime_filter_keypress (GtkIMContext   *context,
+                                                    GdkEventKey    *event);
+static void gtk_im_context_ime_reset               (GtkIMContext   *context);
+static void gtk_im_context_ime_get_preedit_string  (GtkIMContext   *context,
+                                                    gchar         **str,
+                                                    PangoAttrList **attrs,
+                                                    gint           *cursor_pos);
+static void gtk_im_context_ime_focus_in            (GtkIMContext   *context);
+static void gtk_im_context_ime_focus_out           (GtkIMContext   *context);
+static void gtk_im_context_ime_set_cursor_location (GtkIMContext   *context,
+                                                    GdkRectangle   *area);
+static void gtk_im_context_ime_set_use_preedit     (GtkIMContext   *context,
+                                                    gboolean        use_preedit);
+
+/* GtkIMContextIME's private functions */
+static void gtk_im_context_ime_set_preedit_font (GtkIMContext    *context);
+
+static GdkFilterReturn
+gtk_im_context_ime_message_filter               (GdkXEvent       *xevent,
+                                                 GdkEvent        *event,
+                                                 gpointer         data);
+static void get_window_position                 (GdkWindow       *win,
+                                                 gint            *x,
+                                                 gint            *y);
+static void cb_client_widget_hierarchy_changed  (GtkWidget       *widget,
+                                                 GtkWidget       *widget2,
+                                                 GtkIMContextIME *context_ime);
+
+#define GTK_TYPE_IM_CONTEXT_IME (gtk_im_context_ime_get_type ())
+#define GTK_IM_CONTEXT_IME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIME))
+
+G_DEFINE_TYPE_WITH_CODE (GtkIMContextIME, gtk_im_context_ime, GTK_TYPE_IM_CONTEXT,
+                         g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "ime",
+                                                         10))
+
+static void
+gtk_im_context_ime_class_init (GtkIMContextIMEClass *class)
+{
+  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->finalize     = gtk_im_context_ime_finalize;
+  gobject_class->dispose      = gtk_im_context_ime_dispose;
+  gobject_class->set_property = gtk_im_context_ime_set_property;
+  gobject_class->get_property = gtk_im_context_ime_get_property;
+
+  im_context_class->set_client_widget   = gtk_im_context_ime_set_client_widget;
+  im_context_class->filter_keypress     = gtk_im_context_ime_filter_keypress;
+  im_context_class->reset               = gtk_im_context_ime_reset;
+  im_context_class->get_preedit_string  = gtk_im_context_ime_get_preedit_string;
+  im_context_class->focus_in            = gtk_im_context_ime_focus_in;
+  im_context_class->focus_out           = gtk_im_context_ime_focus_out;
+  im_context_class->set_cursor_location = gtk_im_context_ime_set_cursor_location;
+  im_context_class->set_use_preedit     = gtk_im_context_ime_set_use_preedit;
+}
+
+static void
+gtk_im_context_ime_init (GtkIMContextIME *context_ime)
+{
+  context_ime->client_window          = NULL;
+  context_ime->toplevel               = NULL;
+  context_ime->use_preedit            = TRUE;
+  context_ime->preediting             = FALSE;
+  context_ime->opened                 = FALSE;
+  context_ime->focus                  = FALSE;
+  context_ime->cursor_location.x      = 0;
+  context_ime->cursor_location.y      = 0;
+  context_ime->cursor_location.width  = 0;
+  context_ime->cursor_location.height = 0;
+  context_ime->commit_string          = NULL;
+
+  context_ime->priv = g_malloc0 (sizeof (GtkIMContextIMEPrivate));
+  context_ime->priv->conversion_mode  = 0;
+  context_ime->priv->sentence_mode    = 0;
+  context_ime->priv->comp_str         = NULL;
+  context_ime->priv->comp_str_len     = 0;
+  context_ime->priv->read_str         = NULL;
+  context_ime->priv->read_str_len     = 0;
+}
+
+
+static void
+gtk_im_context_ime_dispose (GObject *obj)
+{
+  GtkIMContext *context = GTK_IM_CONTEXT (obj);
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
+
+  if (context_ime->client_window)
+    gtk_im_context_ime_set_client_widget (context, NULL);
+
+  FREE_PREEDIT_BUFFER (context_ime);
+
+  if (G_OBJECT_CLASS (parent_class)->dispose)
+    G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+
+static void
+gtk_im_context_ime_finalize (GObject *obj)
+{
+  /* GtkIMContext *context = GTK_IM_CONTEXT (obj); */
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
+
+  g_free (context_ime->priv);
+  context_ime->priv = NULL;
+
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+
+static void
+gtk_im_context_ime_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
+
+  switch (prop_id)
+    {
+    default:
+      break;
+    }
+}
+
+
+static void
+gtk_im_context_ime_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
+
+  switch (prop_id)
+    {
+    default:
+      break;
+    }
+}
+
+
+GtkIMContext *
+gtk_im_context_ime_new (void)
+{
+  return g_object_new (GTK_TYPE_IM_CONTEXT_IME, NULL);
+}
+
+
+static void
+gtk_im_context_ime_set_client_widget (GtkIMContext *context,
+                                      GtkWidget    *widget)
+{
+  GtkIMContextIME *context_ime;
+  GtkWidget *toplevel;
+  GdkWindow *client_window;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
+  context_ime = GTK_IM_CONTEXT_IME (context);
+  toplevel = gtk_widget_get_toplevel (widget);
+  client_window = gtk_widget_get_window (toplevel);
+
+  if (client_window)
+    {
+      HIMC himc;
+      HWND hwnd;
+
+      hwnd = gdk_win32_window_get_impl_hwnd (client_window);
+      himc = ImmGetContext (hwnd);
+      if (himc)
+       {
+         context_ime->opened = ImmGetOpenStatus (himc);
+         ImmGetConversionStatus (himc,
+                                 &context_ime->priv->conversion_mode,
+                                 &context_ime->priv->sentence_mode);
+         ImmReleaseContext (hwnd, himc);
+       }
+    }
+  else if (context_ime->focus)
+    {
+      gtk_im_context_ime_focus_out (context);
+    }
+
+  context_ime->client_window = client_window;
+}
+
+static gunichar
+_gtk_im_context_ime_dead_key_unichar (guint    keyval,
+                                      gboolean spacing)
+{
+  switch (keyval)
+    {
+#define CASE(keysym, unicode, spacing_unicode) \
+      case GDK_KEY_dead_##keysym: return (spacing) ? spacing_unicode : unicode;
+
+      CASE (grave, 0x0300, 0x0060);
+      CASE (acute, 0x0301, 0x00b4);
+      CASE (circumflex, 0x0302, 0x005e);
+      CASE (tilde, 0x0303, 0x007e);    /* Also used with perispomeni, 0x342. */
+      CASE (macron, 0x0304, 0x00af);
+      CASE (breve, 0x0306, 0x02d8);
+      CASE (abovedot, 0x0307, 0x02d9);
+      CASE (diaeresis, 0x0308, 0x00a8);
+      CASE (hook, 0x0309, 0);
+      CASE (abovering, 0x030A, 0x02da);
+      CASE (doubleacute, 0x030B, 0x2dd);
+      CASE (caron, 0x030C, 0x02c7);
+      CASE (abovecomma, 0x0313, 0);         /* Equivalent to psili */
+      CASE (abovereversedcomma, 0x0314, 0); /* Equivalent to dasia */
+      CASE (horn, 0x031B, 0);  /* Legacy use for psili, 0x313 (or 0x343). */
+      CASE (belowdot, 0x0323, 0);
+      CASE (cedilla, 0x0327, 0x00b8);
+      CASE (ogonek, 0x0328, 0);        /* Legacy use for dasia, 0x314.*/
+      CASE (iota, 0x0345, 0);
+
+#undef CASE
+    default:
+      return 0;
+    }
+}
+
+static void
+_gtk_im_context_ime_commit_unichar (GtkIMContextIME *context_ime,
+                                    gunichar         c)
+{
+  gchar utf8[10];
+  int len;
+
+  if (context_ime->priv->dead_key_keyval != 0)
+    {
+      gunichar combining;
+
+      combining =
+        _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval,
+                                              FALSE);
+      g_unichar_compose (c, combining, &c);
+    }
+
+  len = g_unichar_to_utf8 (c, utf8);
+  utf8[len] = 0;
+
+  g_signal_emit_by_name (context_ime, "commit", utf8);
+  context_ime->priv->dead_key_keyval = 0;
+}
+
+static gboolean
+gtk_im_context_ime_filter_keypress (GtkIMContext *context,
+                                    GdkEventKey  *event)
+{
+  GtkIMContextIME *context_ime;
+  gboolean retval = FALSE;
+  guint32 c;
+  GdkModifierType state;
+  guint keyval;
+
+  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
+  g_return_val_if_fail (event, FALSE);
+
+  if (gdk_event_get_event_type ((GdkEvent *) event) == GDK_KEY_RELEASE)
+    return FALSE;
+
+  gdk_event_get_state ((GdkEvent *) event, &state);
+
+  if (state & GDK_CONTROL_MASK)
+    return FALSE;
+
+  context_ime = GTK_IM_CONTEXT_IME (context);
+
+  if (!context_ime->focus)
+    return FALSE;
+
+  if (!GDK_IS_WINDOW (context_ime->client_window))
+    return FALSE;
+
+  gdk_event_get_keyval ((GdkEvent *) event, &keyval);
+
+  if (keyval == GDK_KEY_space &&
+      context_ime->priv->dead_key_keyval != 0)
+    {
+      c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
+      context_ime->priv->dead_key_keyval = 0;
+      _gtk_im_context_ime_commit_unichar (context_ime, c);
+      return TRUE;
+    }
+
+  c = gdk_keyval_to_unicode (keyval);
+
+  if (c)
+    {
+      _gtk_im_context_ime_commit_unichar (context_ime, c);
+      retval = TRUE;
+    }
+  else if (IS_DEAD_KEY (keyval))
+    {
+      gunichar dead_key;
+
+      dead_key = _gtk_im_context_ime_dead_key_unichar (keyval, FALSE);
+
+      /* Emulate double input of dead keys */
+      if (dead_key && keyval == context_ime->priv->dead_key_keyval)
+        {
+          c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
+          context_ime->priv->dead_key_keyval = 0;
+          _gtk_im_context_ime_commit_unichar (context_ime, c);
+          _gtk_im_context_ime_commit_unichar (context_ime, c);
+        }
+      else
+        context_ime->priv->dead_key_keyval = keyval;
+    }
+
+  return retval;
+}
+
+
+static void
+gtk_im_context_ime_reset (GtkIMContext *context)
+{
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
+  HWND hwnd;
+  HIMC himc;
+
+  if (!context_ime->client_window)
+    return;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return;
+
+  if (context_ime->preediting)
+    {
+      if (ImmGetOpenStatus (himc))
+        ImmNotifyIME (himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+
+      context_ime->preediting = FALSE;
+      g_signal_emit_by_name (context, "preedit-changed");
+    }
+
+  ImmReleaseContext (hwnd, himc);
+}
+
+
+static gchar *
+get_utf8_preedit_string (GtkIMContextIME *context_ime, gint *pos_ret)
+{
+  gchar *utf8str = NULL;
+  HWND hwnd;
+  HIMC himc;
+  gint pos = 0;
+
+  if (pos_ret)
+    *pos_ret = 0;
+
+  if (!context_ime->client_window)
+    return g_strdup ("");
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return g_strdup ("");
+
+  if (context_ime->preediting)
+    {
+      glong len;
+
+      len = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
+      if (len > 0)
+       {
+         GError *error = NULL;
+         gpointer buf = g_alloca (len);
+
+         ImmGetCompositionStringW (himc, GCS_COMPSTR, buf, len);
+         len /= 2;
+         utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
+         if (error)
+           {
+             g_warning ("%s", error->message);
+             g_error_free (error);
+           }
+
+         if (pos_ret)
+           {
+             pos = ImmGetCompositionStringW (himc, GCS_CURSORPOS, NULL, 0);
+             if (pos < 0 || len < pos)
+               {
+                 g_warning ("ImmGetCompositionString: "
+                            "Invalid cursor position!");
+                 pos = 0;
+               }
+           }
+       }
+    }
+
+  if (!utf8str)
+    {
+      utf8str = g_strdup ("");
+      pos = 0;
+    }
+
+  if (pos_ret)
+    *pos_ret = pos;
+
+  ImmReleaseContext (hwnd, himc);
+
+  return utf8str;
+}
+
+
+static PangoAttrList *
+get_pango_attr_list (GtkIMContextIME *context_ime, const gchar *utf8str)
+{
+  PangoAttrList *attrs = pango_attr_list_new ();
+  HWND hwnd;
+  HIMC himc;
+
+  if (!context_ime->client_window)
+    return attrs;
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return attrs;
+
+  if (context_ime->preediting)
+    {
+      const gchar *schr = utf8str, *echr;
+      guint8 *buf;
+      guint16 f_red, f_green, f_blue, b_red, b_green, b_blue;
+      glong len, spos = 0, epos, sidx = 0, eidx;
+      PangoAttribute *attr;
+
+      /*
+       *  get attributes list of IME.
+       */
+      len = ImmGetCompositionStringW (himc, GCS_COMPATTR, NULL, 0);
+      buf = g_alloca (len);
+      ImmGetCompositionStringW (himc, GCS_COMPATTR, buf, len);
+
+      /*
+       *  schr and echr are pointer in utf8str.
+       */
+      for (echr = g_utf8_next_char (utf8str); *schr != '\0';
+           echr = g_utf8_next_char (echr))
+        {
+          /*
+           *  spos and epos are buf(attributes list of IME) position by
+           *  bytes.
+           *  Using the wide-char API, this value is same with UTF-8 offset.
+           */
+         epos = g_utf8_pointer_to_offset (utf8str, echr);
+
+          /*
+           *  sidx and eidx are positions in utf8str by bytes.
+           */
+          eidx = echr - utf8str;
+
+          /*
+           *  convert attributes list to PangoAttriute.
+           */
+          if (*echr == '\0' || buf[spos] != buf[epos])
+            {
+              switch (buf[spos])
+                {
+                case ATTR_TARGET_CONVERTED:
+                  attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
+                  attr->start_index = sidx;
+                  attr->end_index = eidx;
+                  pango_attr_list_change (attrs, attr);
+                  f_red = f_green = f_blue = 0;
+                  b_red = b_green = b_blue = 0xffff;
+                  break;
+                case ATTR_TARGET_NOTCONVERTED:
+                  f_red = f_green = f_blue = 0xffff;
+                  b_red = b_green = b_blue = 0;
+                  break;
+                case ATTR_INPUT_ERROR:
+                  f_red = f_green = f_blue = 0;
+                  b_red = b_green = b_blue = 0x7fff;
+                  break;
+                default:        /* ATTR_INPUT,ATTR_CONVERTED,ATTR_FIXEDCONVERTED */
+                  attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+                  attr->start_index = sidx;
+                  attr->end_index = eidx;
+                  pango_attr_list_change (attrs, attr);
+                  f_red = f_green = f_blue = 0;
+                  b_red = b_green = b_blue = 0xffff;
+                }
+              attr = pango_attr_foreground_new (f_red, f_green, f_blue);
+              attr->start_index = sidx;
+              attr->end_index = eidx;
+              pango_attr_list_change (attrs, attr);
+              attr = pango_attr_background_new (b_red, b_green, b_blue);
+              attr->start_index = sidx;
+              attr->end_index = eidx;
+              pango_attr_list_change (attrs, attr);
+
+              schr = echr;
+              spos = epos;
+              sidx = eidx;
+            }
+        }
+    }
+
+  ImmReleaseContext (hwnd, himc);
+
+  return attrs;
+}
+
+
+static void
+gtk_im_context_ime_get_preedit_string (GtkIMContext   *context,
+                                       gchar         **str,
+                                       PangoAttrList **attrs,
+                                       gint           *cursor_pos)
+{
+  gchar *utf8str = NULL;
+  gint pos = 0;
+  GtkIMContextIME *context_ime;
+
+  context_ime = GTK_IM_CONTEXT_IME (context);
+
+  utf8str = get_utf8_preedit_string (context_ime, &pos);
+
+  if (attrs)
+    *attrs = get_pango_attr_list (context_ime, utf8str);
+
+  if (str)
+    {
+      *str = utf8str;
+    }
+  else
+    {
+      g_free (utf8str);
+      utf8str = NULL;
+    }
+
+  if (cursor_pos)
+    *cursor_pos = pos;
+}
+
+
+static void
+gtk_im_context_ime_focus_in (GtkIMContext *context)
+{
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
+  GdkWindow *toplevel;
+  GtkWidget *widget = NULL;
+  HWND hwnd;
+  HIMC himc;
+
+  if (!GDK_IS_WINDOW (context_ime->client_window))
+    return;
+
+  /* swtich current context */
+  context_ime->focus = TRUE;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return;
+
+  toplevel = gdk_window_get_toplevel (context_ime->client_window);
+  if (GDK_IS_WINDOW (toplevel))
+    {
+      gdk_window_add_filter (toplevel,
+                             gtk_im_context_ime_message_filter, context_ime);
+      context_ime->toplevel = toplevel;
+    }
+  else
+    {
+      g_warning ("gtk_im_context_ime_focus_in(): "
+                 "cannot find toplevel window.");
+      return;
+    }
+
+  /* trace reparenting (probably no need) */
+  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
+  if (GTK_IS_WIDGET (widget))
+    {
+      g_signal_connect (widget, "hierarchy-changed",
+                        G_CALLBACK (cb_client_widget_hierarchy_changed),
+                        context_ime);
+    }
+  else
+    {
+      /* warning? */
+    }
+
+  /* restore preedit context */
+  ImmSetConversionStatus (himc,
+                          context_ime->priv->conversion_mode,
+                          context_ime->priv->sentence_mode);
+
+  if (context_ime->opened)
+    {
+      if (!ImmGetOpenStatus (himc))
+        ImmSetOpenStatus (himc, TRUE);
+      if (context_ime->preediting)
+        {
+          ImmSetCompositionStringW (himc,
+                                   SCS_SETSTR,
+                                   context_ime->priv->comp_str,
+                                   context_ime->priv->comp_str_len, NULL, 0);
+          FREE_PREEDIT_BUFFER (context_ime);
+        }
+    }
+
+  /* clean */
+  ImmReleaseContext (hwnd, himc);
+}
+
+
+static void
+gtk_im_context_ime_focus_out (GtkIMContext *context)
+{
+  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
+  GdkWindow *toplevel;
+  GtkWidget *widget = NULL;
+  HWND hwnd;
+  HIMC himc;
+
+  if (!GDK_IS_WINDOW (context_ime->client_window))
+    return;
+
+  /* swtich current context */
+  context_ime->focus = FALSE;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return;
+
+  /* save preedit context */
+  ImmGetConversionStatus (himc,
+                          &context_ime->priv->conversion_mode,
+                          &context_ime->priv->sentence_mode);
+
+  if (ImmGetOpenStatus (himc))
+    {
+      gboolean preediting = context_ime->preediting;
+
+      if (preediting)
+        {
+          FREE_PREEDIT_BUFFER (context_ime);
+
+          context_ime->priv->comp_str_len
+            = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
+          context_ime->priv->comp_str
+            = g_malloc (context_ime->priv->comp_str_len);
+          ImmGetCompositionStringW (himc, GCS_COMPSTR,
+                                   context_ime->priv->comp_str,
+                                   context_ime->priv->comp_str_len);
+
+          context_ime->priv->read_str_len
+            = ImmGetCompositionStringW (himc, GCS_COMPREADSTR, NULL, 0);
+          context_ime->priv->read_str
+            = g_malloc (context_ime->priv->read_str_len);
+          ImmGetCompositionStringW (himc, GCS_COMPREADSTR,
+                                   context_ime->priv->read_str,
+                                   context_ime->priv->read_str_len);
+        }
+
+      ImmSetOpenStatus (himc, FALSE);
+
+      context_ime->opened = TRUE;
+      context_ime->preediting = preediting;
+    }
+  else
+    {
+      context_ime->opened = FALSE;
+      context_ime->preediting = FALSE;
+    }
+
+  /* remove signal handler */
+  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
+  if (GTK_IS_WIDGET (widget))
+    {
+      g_signal_handlers_disconnect_by_func
+        (G_OBJECT (widget),
+         G_CALLBACK (cb_client_widget_hierarchy_changed), context_ime);
+    }
+
+  /* remove event fileter */
+  toplevel = gdk_window_get_toplevel (context_ime->client_window);
+  if (GDK_IS_WINDOW (toplevel))
+    {
+      gdk_window_remove_filter (toplevel,
+                                gtk_im_context_ime_message_filter,
+                                context_ime);
+      context_ime->toplevel = NULL;
+    }
+  else
+    {
+      g_warning ("gtk_im_context_ime_focus_out(): "
+                 "cannot find toplevel window.");
+    }
+
+  /* clean */
+  ImmReleaseContext (hwnd, himc);
+}
+
+
+static void
+gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
+                                        GdkRectangle *area)
+{
+  gint wx = 0, wy = 0;
+  GtkIMContextIME *context_ime;
+  COMPOSITIONFORM cf;
+  HWND hwnd;
+  HIMC himc;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
+
+  context_ime = GTK_IM_CONTEXT_IME (context);
+  if (area)
+    context_ime->cursor_location = *area;
+
+  if (!context_ime->client_window)
+    return;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return;
+
+  get_window_position (context_ime->client_window, &wx, &wy);
+  cf.dwStyle = CFS_POINT;
+  cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
+  cf.ptCurrentPos.y = wy + context_ime->cursor_location.y;
+  ImmSetCompositionWindow (himc, &cf);
+
+  ImmReleaseContext (hwnd, himc);
+}
+
+
+static void
+gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
+                                    gboolean      use_preedit)
+{
+  GtkIMContextIME *context_ime;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
+  context_ime = GTK_IM_CONTEXT_IME (context);
+
+  context_ime->use_preedit = use_preedit;
+  if (context_ime->preediting)
+    {
+      HWND hwnd;
+      HIMC himc;
+
+      hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+      himc = ImmGetContext (hwnd);
+      if (!himc)
+        return;
+
+      /* FIXME: What to do? */
+
+      ImmReleaseContext (hwnd, himc);
+    }
+}
+
+
+static void
+gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
+{
+  GtkIMContextIME *context_ime;
+  GtkWidget *widget = NULL;
+  HWND hwnd;
+  HIMC himc;
+  HKL ime = GetKeyboardLayout (0);
+  const gchar *lang;
+  gunichar wc;
+  PangoContext *pango_context;
+  PangoFont *font;
+  LOGFONT *logfont;
+  GtkStyleContext *style;
+  PangoFontDescription *font_desc;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
+
+  context_ime = GTK_IM_CONTEXT_IME (context);
+  if (!context_ime->client_window)
+    return;
+
+  gdk_window_get_user_data (context_ime->client_window, (gpointer) &widget);
+  if (!GTK_IS_WIDGET (widget))
+    return;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return;
+
+  /* set font */
+  pango_context = gtk_widget_get_pango_context (widget);
+  if (!pango_context)
+    goto ERROR_OUT;
+
+  /* Try to make sure we use a font that actually can show the
+   * language in question.
+   */
+
+  switch (PRIMARYLANGID (LOWORD (ime)))
+    {
+    case LANG_JAPANESE:
+      lang = "ja"; break;
+    case LANG_KOREAN:
+      lang = "ko"; break;
+    case LANG_CHINESE:
+      switch (SUBLANGID (LOWORD (ime)))
+       {
+       case SUBLANG_CHINESE_TRADITIONAL:
+         lang = "zh_TW"; break;
+       case SUBLANG_CHINESE_SIMPLIFIED:
+         lang = "zh_CN"; break;
+       case SUBLANG_CHINESE_HONGKONG:
+         lang = "zh_HK"; break;
+       case SUBLANG_CHINESE_SINGAPORE:
+         lang = "zh_SG"; break;
+       case SUBLANG_CHINESE_MACAU:
+         lang = "zh_MO"; break;
+       default:
+         lang = "zh"; break;
+       }
+      break;
+    default:
+      lang = ""; break;
+    }
+
+  style = gtk_widget_get_style_context (widget);
+  gtk_style_context_save (style);
+  gtk_style_context_set_state (style, GTK_STATE_FLAG_NORMAL);
+  gtk_style_context_get (style,
+                         "font",
+                         &font_desc,
+                         NULL);
+  gtk_style_context_restore (style);
+
+  if (lang[0])
+    {
+      /* We know what language it is. Look for a character, any
+       * character, that language needs.
+       */
+      PangoLanguage *pango_lang = pango_language_from_string (lang);
+      PangoFontset *fontset =
+        pango_context_load_fontset (pango_context,
+                                                           font_desc,
+                                                           pango_lang);
+      gunichar *sample =
+       g_utf8_to_ucs4 (pango_language_get_sample_string (pango_lang),
+                       -1, NULL, NULL, NULL);
+      wc = 0x4E00;             /* In all CJK languages? */
+      if (sample != NULL)
+       {
+         int i;
+
+         for (i = 0; sample[i]; i++)
+           if (g_unichar_iswide (sample[i]))
+             {
+               wc = sample[i];
+               break;
+             }
+         g_free (sample);
+       }
+      font = pango_fontset_get_font (fontset, wc);
+      g_object_unref (fontset);
+    }
+  else
+    font = pango_context_load_font (pango_context, font_desc);
+
+  if (!font)
+    goto ERROR_OUT;
+
+  logfont = pango_win32_font_logfont (font);
+  if (logfont)
+    ImmSetCompositionFont (himc, logfont);
+
+  g_object_unref (font);
+
+ERROR_OUT:
+  /* clean */
+  ImmReleaseContext (hwnd, himc);
+}
+
+
+static GdkFilterReturn
+gtk_im_context_ime_message_filter (GdkXEvent *xevent,
+                                   GdkEvent  *event,
+                                   gpointer   data)
+{
+  GtkIMContext *context;
+  GtkIMContextIME *context_ime;
+  HWND hwnd;
+  HIMC himc;
+  MSG *msg = (MSG *) xevent;
+  GdkFilterReturn retval = GDK_FILTER_CONTINUE;
+
+  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (data), retval);
+
+  context = GTK_IM_CONTEXT (data);
+  context_ime = GTK_IM_CONTEXT_IME (data);
+  if (!context_ime->focus)
+    return retval;
+
+  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
+  himc = ImmGetContext (hwnd);
+  if (!himc)
+    return retval;
+
+  switch (msg->message)
+    {
+    case WM_IME_COMPOSITION:
+      {
+        gint wx = 0, wy = 0;
+        CANDIDATEFORM cf;
+
+        get_window_position (context_ime->client_window, &wx, &wy);
+        /* FIXME! */
+        {
+          HWND hwnd_top;
+          POINT pt;
+          RECT rc;
+
+          hwnd_top =
+            gdk_win32_window_get_impl_hwnd (gdk_window_get_toplevel
+                                            (context_ime->client_window));
+          GetWindowRect (hwnd_top, &rc);
+          pt.x = wx;
+          pt.y = wy;
+          ClientToScreen (hwnd_top, &pt);
+          wx = pt.x - rc.left;
+          wy = pt.y - rc.top;
+        }
+        cf.dwIndex = 0;
+        cf.dwStyle = CFS_CANDIDATEPOS;
+        cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
+        cf.ptCurrentPos.y = wy + context_ime->cursor_location.y
+          + context_ime->cursor_location.height;
+        ImmSetCandidateWindow (himc, &cf);
+
+        if ((msg->lParam & GCS_COMPSTR))
+          g_signal_emit_by_name (context, "preedit-changed");
+
+        if (msg->lParam & GCS_RESULTSTR)
+          {
+            gsize len;
+            gchar *utf8str = NULL;
+            GError *error = NULL;
+
+            len = ImmGetCompositionStringW (himc, GCS_RESULTSTR, NULL, 0);
+
+            if (len > 0)
+              {
+                gpointer buf = g_alloca (len);
+                ImmGetCompositionStringW (himc, GCS_RESULTSTR, buf, len);
+                len /= 2;
+                context_ime->commit_string = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
+                if (error)
+                  {
+                    g_warning ("%s", error->message);
+                    g_error_free (error);
+                  }
+              }
+
+            if (context_ime->commit_string)
+              retval = TRUE;
+          }
+
+        if (context_ime->use_preedit)
+          retval = TRUE;
+        break;
+      }
+
+    case WM_IME_STARTCOMPOSITION:
+      context_ime->preediting = TRUE;
+      gtk_im_context_ime_set_cursor_location (context, NULL);
+      g_signal_emit_by_name (context, "preedit-start");
+      if (context_ime->use_preedit)
+        retval = TRUE;
+      break;
+
+    case WM_IME_ENDCOMPOSITION:
+      context_ime->preediting = FALSE;
+      g_signal_emit_by_name (context, "preedit-changed");
+      g_signal_emit_by_name (context, "preedit-end");
+
+      if (context_ime->commit_string)
+        {
+          g_signal_emit_by_name (context, "commit", context_ime->commit_string);
+          g_free (context_ime->commit_string);
+          context_ime->commit_string = NULL;
+        }
+
+      if (context_ime->use_preedit)
+        retval = TRUE;
+      break;
+
+    case WM_IME_NOTIFY:
+      switch (msg->wParam)
+        {
+        case IMN_SETOPENSTATUS:
+          context_ime->opened = ImmGetOpenStatus (himc);
+          gtk_im_context_ime_set_preedit_font (context);
+          break;
+
+        default:
+          break;
+        }
+
+    default:
+      break;
+    }
+
+  ImmReleaseContext (hwnd, himc);
+  return retval;
+}
+
+
+/*
+ * x and y must be initialized to 0.
+ */
+static void
+get_window_position (GdkWindow *win, gint *x, gint *y)
+{
+  GdkWindow *parent, *toplevel;
+  gint wx, wy;
+
+  g_return_if_fail (GDK_IS_WINDOW (win));
+  g_return_if_fail (x && y);
+
+  gdk_window_get_position (win, &wx, &wy);
+  *x += wx;
+  *y += wy;
+  parent = gdk_window_get_parent (win);
+  toplevel = gdk_window_get_toplevel (win);
+
+  if (parent && parent != toplevel)
+    get_window_position (parent, x, y);
+}
+
+
+/*
+ *  probably, this handler isn't needed.
+ */
+static void
+cb_client_widget_hierarchy_changed (GtkWidget       *widget,
+                                    GtkWidget       *widget2,
+                                    GtkIMContextIME *context_ime)
+{
+  GdkWindow *new_toplevel;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
+
+  if (!context_ime->client_window)
+    return;
+  if (!context_ime->focus)
+    return;
+
+  new_toplevel = gdk_window_get_toplevel (context_ime->client_window);
+  if (context_ime->toplevel == new_toplevel)
+    return;
+
+  /* remove filter from old toplevel */
+  if (GDK_IS_WINDOW (context_ime->toplevel))
+    {
+      gdk_window_remove_filter (context_ime->toplevel,
+                                gtk_im_context_ime_message_filter,
+                                context_ime);
+    }
+  else
+    {
+    }
+
+  /* add filter to new toplevel */
+  if (GDK_IS_WINDOW (new_toplevel))
+    {
+      gdk_window_add_filter (new_toplevel,
+                             gtk_im_context_ime_message_filter, context_ime);
+    }
+  else
+    {
+    }
+
+  context_ime->toplevel = new_toplevel;
+}
diff --git a/gtk/gtkimcontextime.h b/gtk/gtkimcontextime.h
new file mode 100644 (file)
index 0000000..6bb0365
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * gtkimmoduleime
+ * Copyright (C) 2003 Takuro Ashie
+ * Copyright (C) 2003 Kazuki IWAMOTO
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * $Id$
+ */
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_IM_CONTEXT_IME            gtk_type_im_context_ime
+#define GTK_IM_CONTEXT_IME(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIME))
+#define GTK_IM_CONTEXT_IME_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIMEClass))
+#define GTK_IS_IM_CONTEXT_IME(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_IM_CONTEXT_IME))
+#define GTK_IS_IM_CONTEXT_IME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IM_CONTEXT_IME))
+#define GTK_IM_CONTEXT_IME_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIMEClass))
+
+typedef struct _GtkIMContextIME GtkIMContextIME;
+typedef struct _GtkIMContextIMEPrivate GtkIMContextIMEPrivate;
+typedef struct _GtkIMContextIMEClass GtkIMContextIMEClass;
+
+struct _GtkIMContextIME
+{
+  GtkIMContext object;
+
+  GdkWindow *client_window;
+  GdkWindow *toplevel;
+  guint use_preedit : 1;
+  guint preediting : 1;
+  guint opened : 1;
+  guint focus : 1;
+  GdkRectangle cursor_location;
+  gchar *commit_string;
+
+  GtkIMContextIMEPrivate *priv;
+};
+
+struct _GtkIMContextIMEClass
+{
+  GtkIMContextClass parent_class;
+};
+
+
+void          gtk_im_context_ime_register_type (GTypeModule * type_module);
+GtkIMContext *gtk_im_context_ime_new           (void);
diff --git a/gtk/gtkimcontextquartz.c b/gtk/gtkimcontextquartz.c
new file mode 100644 (file)
index 0000000..2c950fc
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * gtkimmodulequartz
+ * Copyright (C) 2011 Hiroyuki Yamamoto
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * $Id:$
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gtk/gtkimcontextquartz.h"
+#include "gtk/gtkintl.h"
+#include "gtk/gtkimmodule.h"
+
+#include "gdk/quartz/gdkquartz.h"
+#include "gdk/quartz/GdkQuartzView.h"
+
+#define GTK_IM_CONTEXT_TYPE_QUARTZ (type_quartz)
+#define GTK_IM_CONTEXT_QUARTZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, GtkIMContextQuartz))
+#define GTK_IM_CONTEXT_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, GtkIMContextQuartzClass))
+
+
+typedef struct _GtkIMContextQuartz
+{
+  GtkIMContext parent;
+  GtkIMContext *slave;
+  GdkWindow *client_window;
+  gchar *preedit_str;
+  unsigned int cursor_index;
+  unsigned int selected_len;
+  GdkRectangle *cursor_rect;
+  gboolean focused;
+} GtkIMContextQuartz;
+
+typedef struct _GtkIMContextQuartzClass
+{
+  GtkIMContextClass parent_class;
+} GtkIMContextQuartzClass;
+
+G_DEFINE_TYPE_WITH_CODE (GtkIMContextQuartz, gtk_im_context_quartz, GTK_TYPE_IM_CONTEXT,
+                         g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "quartz",
+                                                         10))
+
+static void
+quartz_get_preedit_string (GtkIMContext *context,
+                           gchar **str,
+                           PangoAttrList **attrs,
+                           gint *cursor_pos)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+
+  GTK_NOTE (MISC, g_print ("quartz_get_preedit_string\n"));
+
+  if (str)
+    *str = qc->preedit_str ? g_strdup (qc->preedit_str) : g_strdup ("");
+
+  if (attrs)
+    {
+      *attrs = pango_attr_list_new ();
+      int len = g_utf8_strlen (*str, -1);
+      gchar *ch = *str;
+      if (len > 0)
+        {
+          PangoAttribute *attr;
+          int i = 0;
+          for (;;)
+            {
+              gchar *s = ch;
+              ch = g_utf8_next_char (ch);
+
+              if (i >= qc->cursor_index &&
+                 i < qc->cursor_index + qc->selected_len)
+                attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
+              else
+                attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+
+              attr->start_index = s - *str;
+              if (!*ch)
+                attr->end_index = attr->start_index + strlen (s);
+              else
+                attr->end_index = ch - *str;
+
+              pango_attr_list_change (*attrs, attr);
+
+              if (!*ch)
+                break;
+              i++;
+            }
+        }
+    }
+  if (cursor_pos)
+    *cursor_pos = qc->cursor_index;
+}
+
+static gboolean
+output_result (GtkIMContext *context,
+               GdkWindow *win)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  gboolean retval = FALSE;
+  gchar *fixed_str, *marked_str;
+
+  fixed_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_INSERT_TEXT));
+  marked_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_MARKED_TEXT));
+  if (fixed_str)
+    {
+      GTK_NOTE (MISC, g_print ("tic-insert-text: %s\n", fixed_str));
+      g_free (qc->preedit_str);
+      qc->preedit_str = NULL;
+      g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT, NULL);
+      g_signal_emit_by_name (context, "commit", fixed_str);
+      g_signal_emit_by_name (context, "preedit_changed");
+
+      unsigned int filtered =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               GIC_FILTER_KEY));
+      GTK_NOTE (MISC, g_print ("filtered, %d\n", filtered));
+      if (filtered)
+        retval = TRUE;
+      else
+        retval = FALSE;
+    }
+  if (marked_str)
+    {
+      GTK_NOTE (MISC, g_print ("tic-marked-text: %s\n", marked_str));
+      qc->cursor_index =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               TIC_SELECTED_POS));
+      qc->selected_len =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               TIC_SELECTED_LEN));
+      g_free (qc->preedit_str);
+      qc->preedit_str = g_strdup (marked_str);
+      g_object_set_data (G_OBJECT (win), TIC_MARKED_TEXT, NULL);
+      g_signal_emit_by_name (context, "preedit_changed");
+      retval = TRUE;
+    }
+  if (!fixed_str && !marked_str)
+    {
+      if (qc->preedit_str && strlen (qc->preedit_str) > 0)
+        retval = TRUE;
+    }
+  g_free (fixed_str);
+  g_free (marked_str);
+  return retval;
+}
+
+static gboolean
+quartz_filter_keypress (GtkIMContext *context,
+                        GdkEventKey *event)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  gboolean retval;
+  NSView *nsview;
+  GdkWindow *win;
+
+  GTK_NOTE (MISC, g_print ("quartz_filter_keypress\n"));
+
+  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
+    return FALSE;
+
+  nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  win = (GdkWindow *)[ (GdkQuartzView *)nsview gdkWindow];
+  GTK_NOTE (MISC, g_print ("client_window: %p, win: %p, nsview: %p\n",
+                          qc->client_window, win, nsview));
+
+  NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *)event);
+
+  if (!nsevent)
+    {
+      if (event->hardware_keycode == 0 && event->keyval == 0xffffff)
+        /* update text input changes by mouse events */
+        return output_result (context, win);
+      else
+        return gtk_im_context_filter_keypress (qc->slave, event);
+    }
+
+  if (event->type == GDK_KEY_RELEASE)
+    return FALSE;
+
+  if (event->hardware_keycode == 55)   /* Command */
+    return FALSE;
+
+  NSEventType etype = [nsevent type];
+  if (etype == NSKeyDown)
+    {
+       g_object_set_data (G_OBJECT (win), TIC_IN_KEY_DOWN,
+                                          GUINT_TO_POINTER (TRUE));
+       [nsview keyDown: nsevent];
+    }
+  /* JIS_Eisu || JIS_Kana */
+  if (event->hardware_keycode == 102 || event->hardware_keycode == 104)
+    return FALSE;
+
+  retval = output_result(context, win);
+  g_object_set_data (G_OBJECT (win), TIC_IN_KEY_DOWN,
+                                     GUINT_TO_POINTER (FALSE));
+  GTK_NOTE (MISC, g_print ("quartz_filter_keypress done\n"));
+
+  return retval;
+}
+
+static void
+discard_preedit (GtkIMContext *context)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+
+  if (!qc->client_window)
+    return;
+
+  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
+    return;
+
+  NSView *nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  if (!nsview)
+    return;
+
+  /* reset any partial input for this NSView */
+  [(GdkQuartzView *)nsview unmarkText];
+  NSInputManager *currentInputManager = [NSInputManager currentInputManager];
+  [currentInputManager markedTextAbandoned:nsview];
+
+  if (qc->preedit_str && strlen (qc->preedit_str) > 0)
+    {
+      g_signal_emit_by_name (context, "commit", qc->preedit_str);
+
+      g_free (qc->preedit_str);
+      qc->preedit_str = NULL;
+      g_signal_emit_by_name (context, "preedit_changed");
+    }
+}
+
+static void
+quartz_reset (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_reset\n"));
+  discard_preedit (context);
+}
+
+static void
+quartz_set_client_window (GtkIMContext *context, GtkWidget *widget)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+
+  GTK_NOTE (MISC, g_print ("quartz_set_client_window: %p\n", widget));
+
+  qc->client_window = gtk_widget_get_parent_window (widget);
+}
+
+static void
+quartz_focus_in (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_focus_in\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  qc->focused = TRUE;
+}
+
+static void
+quartz_focus_out (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_focus_out\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  qc->focused = FALSE;
+
+  /* Commit any partially built strings or it'll mess up other GTK+ widgets in the window */
+  discard_preedit (context);
+}
+
+static void
+quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  gint x, y;
+  NSView *nsview;
+  GdkWindow *win;
+
+  GTK_NOTE (MISC, g_print ("quartz_set_cursor_location\n"));
+
+  if (!qc->client_window)
+    return;
+
+  if (!qc->focused)
+    return;
+
+  qc->cursor_rect->x = area->x;
+  qc->cursor_rect->y = area->y;
+  qc->cursor_rect->width = area->width;
+  qc->cursor_rect->height = area->height;
+
+  gdk_window_get_origin (qc->client_window, &x, &y);
+
+  qc->cursor_rect->x = area->x + x;
+  qc->cursor_rect->y = area->y + y;
+
+  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
+    return;
+
+  nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  win = (GdkWindow *)[ (GdkQuartzView*)nsview gdkWindow];
+  g_object_set_data (G_OBJECT (win), GIC_CURSOR_RECT, qc->cursor_rect);
+}
+
+static void
+quartz_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
+{
+  GTK_NOTE (MISC, g_print ("quartz_set_use_preedit: %d\n", use_preedit));
+}
+
+static void
+commit_cb (GtkIMContext *context, const gchar *str, GtkIMContextQuartz *qc)
+{
+  g_signal_emit_by_name (qc, "commit", str);
+}
+
+static void
+imquartz_finalize (GObject *obj)
+{
+  GTK_NOTE (MISC, g_print ("imquartz_finalize\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (obj);
+  g_free (qc->preedit_str);
+  qc->preedit_str = NULL;
+  g_free (qc->cursor_rect);
+  qc->cursor_rect = NULL;
+
+  g_signal_handlers_disconnect_by_func (qc->slave, (gpointer)commit_cb, qc);
+  g_object_unref (qc->slave);
+
+  gtk_im_context_quartz_parent_class->finalize (obj);
+}
+
+static void
+gtk_im_context_quartz_class_init (GtkIMContextQuartzClass *class)
+{
+  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_class_init\n"));
+
+  GtkIMContextClass *klass = GTK_IM_CONTEXT_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  klass->get_preedit_string = quartz_get_preedit_string;
+  klass->filter_keypress = quartz_filter_keypress;
+  klass->reset = quartz_reset;
+  klass->set_client_widget = quartz_set_client_window;
+  klass->focus_in = quartz_focus_in;
+  klass->focus_out = quartz_focus_out;
+  klass->set_cursor_location = quartz_set_cursor_location;
+  klass->set_use_preedit = quartz_set_use_preedit;
+
+  object_class->finalize = imquartz_finalize;
+}
+
+static void
+gtk_im_context_quartz_init (GtkIMContextQuartz *qc)
+{
+  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_init\n"));
+
+  qc->preedit_str = g_strdup ("");
+  qc->cursor_index = 0;
+  qc->selected_len = 0;
+  qc->cursor_rect = g_malloc (sizeof (GdkRectangle));
+  qc->focused = FALSE;
+
+  qc->slave = g_object_new (GTK_TYPE_IM_CONTEXT_SIMPLE, NULL);
+  g_signal_connect (G_OBJECT (qc->slave), "commit", G_CALLBACK (commit_cb), qc);
+}
diff --git a/gtk/gtkimcontextquartz.h b/gtk/gtkimcontextquartz.h
new file mode 100644 (file)
index 0000000..a051543
--- /dev/null
@@ -0,0 +1,29 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2018 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_IM_CONTEXT_QUARTZ_H__
+#define __GTK_IM_CONTEXT_QUARTZ_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+GType         gtk_im_context_quartz_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_IM_CONTEXT_QUARTZ_H__ */
diff --git a/gtk/gtkimcontextwayland.c b/gtk/gtkimcontextwayland.c
new file mode 100644 (file)
index 0000000..6ffd288
--- /dev/null
@@ -0,0 +1,622 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <wayland-client-protocol.h>
+
+#include "gtk/gtkimcontextwayland.h"
+#include "gtk/gtkintl.h"
+#include "gtk/gtkimmodule.h"
+
+#include "gdk/wayland/gdkwayland.h"
+#include "gtk-text-input-client-protocol.h"
+
+typedef struct _GtkIMContextWaylandGlobal GtkIMContextWaylandGlobal;
+typedef struct _GtkIMContextWayland GtkIMContextWayland;
+typedef struct _GtkIMContextWaylandClass GtkIMContextWaylandClass;
+
+struct _GtkIMContextWaylandGlobal
+{
+  struct wl_display *display;
+  struct wl_registry *registry;
+  struct gtk_text_input_manager *text_input_manager;
+  struct gtk_text_input *text_input;
+  uint32_t enter_serial;
+
+  GtkIMContext *current;
+};
+
+struct _GtkIMContextWaylandClass
+{
+  GtkIMContextSimpleClass parent_class;
+};
+
+struct _GtkIMContextWayland
+{
+  GtkIMContextSimple parent_instance;
+  GtkWidget *widget;
+
+  GtkGesture *gesture;
+  gdouble press_x;
+  gdouble press_y;
+
+  struct {
+    gchar *text;
+    gint cursor_idx;
+  } surrounding;
+
+  struct {
+    gchar *text;
+    gint cursor_idx;
+  } preedit;
+
+  cairo_rectangle_int_t cursor_rect;
+  guint use_preedit : 1;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GtkIMContextWayland, gtk_im_context_wayland, GTK_TYPE_IM_CONTEXT,
+                         g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "wayland",
+                                                         10));
+
+static GtkIMContextWaylandGlobal *global = NULL;
+
+#define GTK_IM_CONTEXT_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), gtk_im_context_wayland__get_type (), GtkIMContextWayland))
+
+static void
+reset_preedit (GtkIMContextWayland *context)
+{
+  g_clear_pointer (&context->preedit.text, g_free);
+  context->preedit.cursor_idx = 0;
+  g_signal_emit_by_name (context, "preedit-changed");
+}
+
+static void
+text_input_enter (void                     *data,
+                  struct gtk_text_input    *text_input,
+                  uint32_t                  serial,
+                  struct wl_surface        *surface)
+{
+  GtkIMContextWaylandGlobal *global = data;
+
+  global->enter_serial = serial;
+}
+
+static void
+text_input_leave (void                     *data,
+                  struct gtk_text_input    *text_input,
+                  uint32_t                  serial,
+                  struct wl_surface        *surface)
+{
+  GtkIMContextWayland *context;
+
+  if (!global->current)
+    return;
+
+  context = GTK_IM_CONTEXT_WAYLAND (global->current);
+  reset_preedit (context);
+}
+
+static void
+text_input_preedit (void                     *data,
+                    struct gtk_text_input    *text_input,
+                    const char               *text,
+                    guint                     cursor)
+{
+  GtkIMContextWayland *context;
+  gboolean state_change;
+
+  if (!global->current)
+    return;
+
+  context = GTK_IM_CONTEXT_WAYLAND (global->current);
+  if (!text && !context->preedit.text)
+    return;
+
+  state_change = ((text == NULL) != (context->preedit.text == NULL));
+
+  if (state_change && !context->preedit.text)
+    g_signal_emit_by_name (context, "preedit-start");
+
+  g_free (context->preedit.text);
+  context->preedit.text = g_strdup (text);
+  context->preedit.cursor_idx = cursor;
+
+  g_signal_emit_by_name (context, "preedit-changed");
+
+  if (state_change && !context->preedit.text)
+    g_signal_emit_by_name (context, "preedit-end");
+}
+
+static void
+text_input_commit (void                     *data,
+                   struct gtk_text_input    *text_input,
+                   const char               *text)
+{
+  GtkIMContextWaylandGlobal *global = data;
+
+  if (global->current && text)
+    g_signal_emit_by_name (global->current, "commit", text);
+}
+
+static void
+text_input_delete_surrounding_text (void                     *data,
+                                    struct gtk_text_input    *text_input,
+                                    uint32_t                  offset,
+                                    uint32_t                  len)
+{
+  GtkIMContextWaylandGlobal *global = data;
+
+  if (global->current)
+    g_signal_emit_by_name (global->current, "delete-surrounding", offset, len);
+}
+
+static const struct gtk_text_input_listener text_input_listener = {
+  text_input_enter,
+  text_input_leave,
+  text_input_preedit,
+  text_input_commit,
+  text_input_delete_surrounding_text
+};
+
+static void
+registry_handle_global (void               *data,
+                        struct wl_registry *registry,
+                        uint32_t            id,
+                        const char         *interface,
+                        uint32_t            version)
+{
+  GtkIMContextWaylandGlobal *global = data;
+  GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
+
+  if (strcmp (interface, "gtk_text_input_manager") == 0)
+    {
+      global->text_input_manager =
+        wl_registry_bind (global->registry, id,
+                          &gtk_text_input_manager_interface, 1);
+      global->text_input =
+        gtk_text_input_manager_get_text_input (global->text_input_manager,
+                                               gdk_wayland_seat_get_wl_seat (seat));
+      gtk_text_input_add_listener (global->text_input,
+                                   &text_input_listener, global);
+    }
+}
+
+static void
+registry_handle_global_remove (void               *data,
+                               struct wl_registry *registry,
+                               uint32_t            id)
+{
+  GtkIMContextWaylandGlobal *global = data;
+
+  gtk_text_input_destroy (global->text_input);
+  global->text_input = NULL;
+
+  gtk_text_input_manager_destroy (global->text_input_manager);
+  global->text_input_manager = NULL;
+}
+
+static const struct wl_registry_listener registry_listener = {
+    registry_handle_global,
+    registry_handle_global_remove
+};
+
+static void
+gtk_im_context_wayland_global_init (GdkDisplay *display)
+{
+  if (global != NULL)
+    return;
+
+  global = g_new0 (GtkIMContextWaylandGlobal, 1);
+  global->display = gdk_wayland_display_get_wl_display (display);
+  global->registry = wl_display_get_registry (global->display);
+
+  wl_registry_add_listener (global->registry, &registry_listener, global);
+}
+
+static void
+notify_surrounding_text (GtkIMContextWayland *context)
+{
+  if (!global || !global->text_input)
+    return;
+  if (global->current != GTK_IM_CONTEXT (context))
+    return;
+  if (!context->surrounding.text)
+    return;
+
+  gtk_text_input_set_surrounding_text (global->text_input,
+                                       context->surrounding.text,
+                                       context->surrounding.cursor_idx,
+                                       context->surrounding.cursor_idx);
+}
+
+static void
+notify_cursor_location (GtkIMContextWayland *context)
+{
+  cairo_rectangle_int_t rect;
+
+  if (!global || !global->text_input)
+    return;
+  if (global->current != GTK_IM_CONTEXT (context))
+    return;
+  if (!context->widget)
+    return;
+
+  rect = context->cursor_rect;
+  gtk_widget_translate_coordinates (context->widget,
+                                    gtk_widget_get_toplevel (context->widget),
+                                    rect.x, rect.y,
+                                    &rect.x, &rect.y);
+
+  gtk_text_input_set_cursor_rectangle (global->text_input,
+                                       rect.x, rect.y,
+                                       rect.width, rect.height);
+}
+
+static uint32_t
+translate_hints (GtkInputHints   input_hints,
+                 GtkInputPurpose purpose)
+{
+  uint32_t hints = 0;
+
+  if (input_hints & GTK_INPUT_HINT_SPELLCHECK)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_SPELLCHECK;
+  if (input_hints & GTK_INPUT_HINT_WORD_COMPLETION)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_COMPLETION;
+  if (input_hints & GTK_INPUT_HINT_LOWERCASE)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
+  if (input_hints & GTK_INPUT_HINT_UPPERCASE_CHARS)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
+  if (input_hints & GTK_INPUT_HINT_UPPERCASE_WORDS)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_TITLECASE;
+  if (input_hints & GTK_INPUT_HINT_UPPERCASE_SENTENCES)
+    hints |= GTK_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
+
+  if (purpose == GTK_INPUT_PURPOSE_PIN ||
+      purpose == GTK_INPUT_PURPOSE_PASSWORD)
+    {
+      hints |= (GTK_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT |
+                GTK_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA);
+    }
+
+  return hints;
+}
+
+static uint32_t
+translate_purpose (GtkInputPurpose purpose)
+{
+  switch (purpose)
+    {
+    case GTK_INPUT_PURPOSE_FREE_FORM:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
+    case GTK_INPUT_PURPOSE_ALPHA:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_ALPHA;
+    case GTK_INPUT_PURPOSE_DIGITS:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
+    case GTK_INPUT_PURPOSE_NUMBER:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
+    case GTK_INPUT_PURPOSE_PHONE:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
+    case GTK_INPUT_PURPOSE_URL:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_URL;
+    case GTK_INPUT_PURPOSE_EMAIL:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
+    case GTK_INPUT_PURPOSE_NAME:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NAME;
+    case GTK_INPUT_PURPOSE_PASSWORD:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
+    case GTK_INPUT_PURPOSE_PIN:
+      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PIN;
+    default:
+      g_assert_not_reached ();
+    }
+
+  return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
+}
+
+static void
+notify_content_type (GtkIMContextWayland *context)
+{
+  GtkInputHints hints;
+  GtkInputPurpose purpose;
+
+  if (global->current != GTK_IM_CONTEXT (context))
+    return;
+
+  g_object_get (context,
+                "input-hints", &hints,
+                "input-purpose", &purpose,
+                NULL);
+
+  gtk_text_input_set_content_type (global->text_input,
+                                   translate_hints (hints, purpose),
+                                   translate_purpose (purpose));
+}
+
+static void
+commit_state (GtkIMContextWayland *context)
+{
+  if (global->current != GTK_IM_CONTEXT (context))
+    return;
+  gtk_text_input_commit (global->text_input);
+}
+
+static void
+enable_text_input (GtkIMContextWayland *context,
+                   gboolean             toggle_panel)
+{
+  guint flags = 0;
+
+  if (context->use_preedit)
+    flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_CAN_SHOW_PREEDIT;
+  if (toggle_panel)
+    flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_TOGGLE_INPUT_PANEL;
+
+  gtk_text_input_enable (global->text_input,
+                         global->enter_serial,
+                         flags);
+}
+
+static void
+gtk_im_context_wayland_finalize (GObject *object)
+{
+  GtkIMContextWayland *context = GTK_IM_CONTEXT_WAYLAND (object);
+
+  g_clear_object (&context->widget);
+  g_clear_object (&context->gesture);
+
+  G_OBJECT_CLASS (gtk_im_context_wayland_parent_class)->finalize (object);
+}
+
+static void
+pressed_cb (GtkGestureMultiPress *gesture,
+            gint                  n_press,
+            gdouble               x,
+            gdouble               y,
+            GtkIMContextWayland  *context)
+{
+  if (n_press == 1)
+    {
+      context->press_x = x;
+      context->press_y = y;
+    }
+}
+
+static void
+released_cb (GtkGestureMultiPress *gesture,
+             gint                  n_press,
+             gdouble               x,
+             gdouble               y,
+             GtkIMContextWayland  *context)
+{
+  GtkInputHints hints;
+
+  g_object_get (context, "input-hints", &hints, NULL);
+
+  if (n_press == 1 &&
+      (hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
+      !gtk_drag_check_threshold (context->widget,
+                                 context->press_x,
+                                 context->press_y,
+                                 x, y))
+    {
+      enable_text_input (GTK_IM_CONTEXT_WAYLAND (context), TRUE);
+    }
+}
+
+static void
+gtk_im_context_wayland_set_client_widget (GtkIMContext *context,
+                                          GtkWidget    *widget)
+{
+  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  if (widget == context_wayland->widget)
+    return;
+
+  if (context_wayland->widget && context_wayland->widget != widget)
+    g_clear_object (&context_wayland->gesture);
+
+  g_set_object (&context_wayland->widget, widget);
+
+  if (widget)
+    {
+      GtkGesture *gesture;
+
+      gesture = gtk_gesture_multi_press_new (widget);
+      gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
+                                                  GTK_PHASE_CAPTURE);
+      g_signal_connect (gesture, "pressed",
+                        G_CALLBACK (pressed_cb), context);
+      g_signal_connect (gesture, "released",
+                        G_CALLBACK (released_cb), context);
+      context_wayland->gesture = gesture;
+    }
+}
+
+static void
+gtk_im_context_wayland_get_preedit_string (GtkIMContext   *context,
+                                           gchar         **str,
+                                           PangoAttrList **attrs,
+                                           gint           *cursor_pos)
+{
+  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+  const char *preedit_str;
+
+  GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->get_preedit_string (context, str, attrs, cursor_pos);
+
+  /* If the parent implementation returns a len>0 string, go with it */
+  if (str && *str && **str)
+    return;
+
+  preedit_str =
+    context_wayland->preedit.text ? context_wayland->preedit.text : "";
+
+  if (str)
+    *str = g_strdup (preedit_str);
+  if (cursor_pos)
+    *cursor_pos = context_wayland->preedit.cursor_idx;
+
+  if (attrs)
+    {
+      *attrs = pango_attr_list_new ();
+      pango_attr_list_insert (*attrs,
+                              pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
+    }
+}
+
+static gboolean
+gtk_im_context_wayland_filter_keypress (GtkIMContext *context,
+                                        GdkEventKey  *key)
+{
+  /* This is done by the compositor */
+  return GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->filter_keypress (context, key);
+}
+
+static void
+gtk_im_context_wayland_focus_in (GtkIMContext *context)
+{
+  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  if (global->current == context)
+    return;
+  if (!global->text_input)
+    return;
+
+  global->current = context;
+  enable_text_input (context_wayland, FALSE);
+  notify_content_type (context_wayland);
+  notify_surrounding_text (context_wayland);
+  notify_cursor_location (context_wayland);
+  commit_state (context_wayland);
+}
+
+static void
+gtk_im_context_wayland_focus_out (GtkIMContext *context)
+{
+  if (global->current != context)
+    return;
+
+  gtk_text_input_disable (global->text_input);
+  global->current = NULL;
+}
+
+static void
+gtk_im_context_wayland_reset (GtkIMContext *context)
+{
+  reset_preedit (GTK_IM_CONTEXT_WAYLAND (context));
+
+  GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->reset (context);
+}
+
+static void
+gtk_im_context_wayland_set_cursor_location (GtkIMContext *context,
+                                            GdkRectangle *rect)
+{
+  GtkIMContextWayland *context_wayland;
+
+  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  context_wayland->cursor_rect = *rect;
+  notify_cursor_location (context_wayland);
+  commit_state (context_wayland);
+}
+
+static void
+gtk_im_context_wayland_set_use_preedit (GtkIMContext *context,
+                                        gboolean      use_preedit)
+{
+  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  context_wayland->use_preedit = !!use_preedit;
+}
+
+static void
+gtk_im_context_wayland_set_surrounding (GtkIMContext *context,
+                                        const gchar  *text,
+                                        gint          len,
+                                        gint          cursor_index)
+{
+  GtkIMContextWayland *context_wayland;
+
+  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  g_free (context_wayland->surrounding.text);
+  context_wayland->surrounding.text = g_strdup (text);
+  context_wayland->surrounding.cursor_idx = cursor_index;
+
+  notify_surrounding_text (context_wayland);
+  commit_state (context_wayland);
+}
+
+static gboolean
+gtk_im_context_wayland_get_surrounding (GtkIMContext  *context,
+                                        gchar        **text,
+                                        gint          *cursor_index)
+{
+  GtkIMContextWayland *context_wayland;
+
+  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
+
+  if (!context_wayland->surrounding.text)
+    return FALSE;
+
+  *text = context_wayland->surrounding.text;
+  *cursor_index = context_wayland->surrounding.cursor_idx;
+  return TRUE;
+}
+
+static void
+gtk_im_context_wayland_class_init (GtkIMContextWaylandClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass);
+
+  object_class->finalize = gtk_im_context_wayland_finalize;
+
+  im_context_class->set_client_widget = gtk_im_context_wayland_set_client_widget;
+  im_context_class->get_preedit_string = gtk_im_context_wayland_get_preedit_string;
+  im_context_class->filter_keypress = gtk_im_context_wayland_filter_keypress;
+  im_context_class->focus_in = gtk_im_context_wayland_focus_in;
+  im_context_class->focus_out = gtk_im_context_wayland_focus_out;
+  im_context_class->reset = gtk_im_context_wayland_reset;
+  im_context_class->set_cursor_location = gtk_im_context_wayland_set_cursor_location;
+  im_context_class->set_use_preedit = gtk_im_context_wayland_set_use_preedit;
+  im_context_class->set_surrounding = gtk_im_context_wayland_set_surrounding;
+  im_context_class->get_surrounding = gtk_im_context_wayland_get_surrounding;
+}
+
+static void
+on_content_type_changed (GtkIMContextWayland *context)
+{
+  notify_content_type (context);
+  commit_state (context);
+}
+
+static void
+gtk_im_context_wayland_init (GtkIMContextWayland *context)
+{
+  gtk_im_context_wayland_global_init (gdk_display_get_default ());
+
+  context->use_preedit = TRUE;
+  g_signal_connect_swapped (context, "notify::input-purpose",
+                            G_CALLBACK (on_content_type_changed), context);
+  g_signal_connect_swapped (context, "notify::input-hints",
+                            G_CALLBACK (on_content_type_changed), context);
+}
diff --git a/gtk/gtkimcontextwayland.h b/gtk/gtkimcontextwayland.h
new file mode 100644 (file)
index 0000000..b3a75d3
--- /dev/null
@@ -0,0 +1,29 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2018 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_IM_CONTEXT_WAYLAND_H__
+#define __GTK_IM_CONTEXT_WAYLAND_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+GType         gtk_im_context_wayland_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_IM_CONTEXT_WAYLAND_H__ */
diff --git a/gtk/gtkimcontextxim.c b/gtk/gtkimcontextxim.c
new file mode 100644 (file)
index 0000000..c258df6
--- /dev/null
@@ -0,0 +1,1771 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "locale.h"
+#include <string.h>
+#include <stdlib.h>
+
+#include "gtkimcontextxim.h"
+#include "gtkimmodule.h"
+
+#include "gtk/gtkintl.h"
+
+typedef struct _StatusWindow StatusWindow;
+typedef struct _GtkXIMInfo GtkXIMInfo;
+
+struct _GtkIMContextXIM
+{
+  GtkIMContext object;
+
+  GtkXIMInfo *im_info;
+
+  gchar *locale;
+  gchar *mb_charset;
+
+  GdkWindow *client_window;
+  Window client_window_xid;
+  GtkWidget *client_widget;
+
+  /* The status window for this input context; we claim the
+   * status window when we are focused and have created an XIC
+   */
+  StatusWindow *status_window;
+
+  gint preedit_size;
+  gint preedit_length;
+  gunichar *preedit_chars;
+  XIMFeedback *feedbacks;
+
+  gint preedit_cursor;
+
+  XIMCallback preedit_start_callback;
+  XIMCallback preedit_done_callback;
+  XIMCallback preedit_draw_callback;
+  XIMCallback preedit_caret_callback;
+
+  XIMCallback status_start_callback;
+  XIMCallback status_done_callback;
+  XIMCallback status_draw_callback;
+
+  XIMCallback string_conversion_callback;
+
+  XIC ic;
+
+  guint filter_key_release : 1;
+  guint use_preedit : 1;
+  guint finalizing : 1;
+  guint in_toplevel : 1;
+  guint has_focus : 1;
+};
+
+struct _GtkXIMInfo
+{
+  GdkDisplay *display;
+  XIM im;
+  char *locale;
+  XIMStyle preedit_style_setting;
+  XIMStyle status_style_setting;
+  XIMStyle style;
+  GtkSettings *settings;
+  gulong status_set;
+  gulong preedit_set;
+  gulong display_closed_cb;
+  XIMStyles *xim_styles;
+  GSList *ics;
+
+  guint reconnecting :1;
+  guint supports_string_conversion;
+};
+
+/* A context status window; these are kept in the status_windows list. */
+struct _StatusWindow
+{
+  GtkWidget *window;
+
+  /* Toplevel window to which the status window corresponds */
+  GtkWidget *toplevel;
+
+  /* Currently focused GtkIMContextXIM for the toplevel, if any */
+  GtkIMContextXIM *context;
+};
+
+static void     gtk_im_context_xim_finalize           (GObject               *obj);
+static void     gtk_im_context_xim_set_client_widget  (GtkIMContext          *context,
+                                                       GtkWidget             *widget);
+static gboolean gtk_im_context_xim_filter_keypress    (GtkIMContext          *context,
+                                                      GdkEventKey           *key);
+static void     gtk_im_context_xim_reset              (GtkIMContext          *context);
+static void     gtk_im_context_xim_focus_in           (GtkIMContext          *context);
+static void     gtk_im_context_xim_focus_out          (GtkIMContext          *context);
+static void     gtk_im_context_xim_set_cursor_location (GtkIMContext          *context,
+                                                      GdkRectangle             *area);
+static void     gtk_im_context_xim_set_use_preedit    (GtkIMContext          *context,
+                                                      gboolean               use_preedit);
+static void     gtk_im_context_xim_get_preedit_string (GtkIMContext          *context,
+                                                      gchar                **str,
+                                                      PangoAttrList        **attrs,
+                                                      gint                  *cursor_pos);
+
+static void reinitialize_ic      (GtkIMContextXIM *context_xim);
+static void set_ic_client_window (GtkIMContextXIM *context_xim,
+                                 GdkWindow       *client_window);
+
+static void setup_styles (GtkXIMInfo *info);
+
+static void update_client_widget   (GtkIMContextXIM *context_xim);
+static void update_status_window   (GtkIMContextXIM *context_xim);
+
+static StatusWindow *status_window_get      (GtkWidget    *toplevel);
+static void          status_window_free     (StatusWindow *status_window);
+static void          status_window_set_text (StatusWindow *status_window,
+                                            const gchar  *text);
+
+static void xim_destroy_callback   (XIM      xim,
+                                   XPointer client_data,
+                                   XPointer call_data);
+
+static XIC       gtk_im_context_xim_get_ic            (GtkIMContextXIM *context_xim);
+static void           xim_info_display_closed (GdkDisplay *display,
+                                              gboolean    is_error,
+                                              GtkXIMInfo *info);
+
+G_DEFINE_TYPE_WITH_CODE (GtkIMContextXIM, gtk_im_context_xim, GTK_TYPE_IM_CONTEXT,
+                         g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
+                                                         g_define_type_id,
+                                                         "xim",
+                                                         10))
+
+static GSList *open_ims = NULL;
+
+/* List of status windows for different toplevels */
+static GSList *status_windows = NULL;
+
+#define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \
+                     XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone)
+#define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \
+                     XIMStatusNothing | XIMStatusNone)
+#define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \
+                     XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone)
+
+static XIMStyle
+choose_better_style (XIMStyle style1, XIMStyle style2)
+{
+  XIMStyle s1, s2, u;
+
+  if (style1 == 0) return style2;
+  if (style2 == 0) return style1;
+  if ((style1 & (PREEDIT_MASK | STATUS_MASK))
+       == (style2 & (PREEDIT_MASK | STATUS_MASK)))
+    return style1;
+
+  s1 = style1 & PREEDIT_MASK;
+  s2 = style2 & PREEDIT_MASK;
+  u = s1 | s2;
+  if (s1 != s2) {
+    if (u & XIMPreeditCallbacks)
+      return (s1 == XIMPreeditCallbacks) ? style1 : style2;
+    else if (u & XIMPreeditPosition)
+      return (s1 == XIMPreeditPosition) ? style1 :style2;
+    else if (u & XIMPreeditArea)
+      return (s1 == XIMPreeditArea) ? style1 : style2;
+    else if (u & XIMPreeditNothing)
+      return (s1 == XIMPreeditNothing) ? style1 : style2;
+    else if (u & XIMPreeditNone)
+      return (s1 == XIMPreeditNone) ? style1 : style2;
+  } else {
+    s1 = style1 & STATUS_MASK;
+    s2 = style2 & STATUS_MASK;
+    u = s1 | s2;
+    if (u & XIMStatusCallbacks)
+      return (s1 == XIMStatusCallbacks) ? style1 : style2;
+    else if (u & XIMStatusArea)
+      return (s1 == XIMStatusArea) ? style1 : style2;
+    else if (u & XIMStatusNothing)
+      return (s1 == XIMStatusNothing) ? style1 : style2;
+    else if (u & XIMStatusNone)
+      return (s1 == XIMStatusNone) ? style1 : style2;
+  }
+  return 0; /* Get rid of stupid warning */
+}
+
+static void
+reinitialize_all_ics (GtkXIMInfo *info)
+{
+  GSList *tmp_list;
+
+  for (tmp_list = info->ics; tmp_list; tmp_list = tmp_list->next)
+    reinitialize_ic (tmp_list->data);
+}
+
+static void
+setup_styles (GtkXIMInfo *info)
+{
+  int i;
+  unsigned long settings_preference;
+  XIMStyles *xim_styles = info->xim_styles;
+
+  settings_preference = info->status_style_setting|info->preedit_style_setting;
+  info->style = 0;
+  if (xim_styles)
+    {
+      for (i = 0; i < xim_styles->count_styles; i++)
+       if ((xim_styles->supported_styles[i] & ALLOWED_MASK) == xim_styles->supported_styles[i])
+         {
+           if (settings_preference == xim_styles->supported_styles[i])
+             {
+               info->style = settings_preference;
+               break;
+             }
+           info->style = choose_better_style (info->style,
+                                              xim_styles->supported_styles[i]);
+         }
+    }
+  if (info->style == 0)
+    info->style = XIMPreeditNothing | XIMStatusNothing;
+}
+
+static void
+setup_im (GtkXIMInfo *info)
+{
+  XIMValuesList *ic_values = NULL;
+  XIMCallback im_destroy_callback;
+  GdkDisplay *display;
+
+  if (info->im == NULL)
+    return;
+
+  im_destroy_callback.client_data = (XPointer)info;
+  im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
+  XSetIMValues (info->im,
+               XNDestroyCallback, &im_destroy_callback,
+               NULL);
+
+  XGetIMValues (info->im,
+               XNQueryInputStyle, &info->xim_styles,
+               XNQueryICValuesList, &ic_values,
+               NULL);
+
+  info->supports_string_conversion = FALSE;
+  if (ic_values)
+    {
+      int i;
+
+      for (i = 0; i < ic_values->count_values; i++)
+       if (strcmp (ic_values->supported_values[i],
+                   XNStringConversionCallback) == 0)
+         {
+           info->supports_string_conversion = TRUE;
+           break;
+         }
+
+#if 0
+      for (i = 0; i < ic_values->count_values; i++)
+       g_print ("%s\n", ic_values->supported_values[i]);
+      for (i = 0; i < xim_styles->count_styles; i++)
+       g_print ("%#x\n", xim_styles->supported_styles[i]);
+#endif
+
+      XFree (ic_values);
+    }
+
+  info->status_style_setting = XIMStatusCallbacks;
+  info->preedit_style_setting = XIMPreeditCallbacks;
+  setup_styles (info);
+  reinitialize_all_ics (info);
+
+  display = info->display;
+  info->display_closed_cb = g_signal_connect (display, "closed",
+                                             G_CALLBACK (xim_info_display_closed), info);
+}
+
+static void
+xim_info_display_closed (GdkDisplay *display,
+                        gboolean    is_error,
+                        GtkXIMInfo *info)
+{
+  GSList *ics, *tmp_list;
+
+  open_ims = g_slist_remove (open_ims, info);
+
+  ics = info->ics;
+  info->ics = NULL;
+
+  for (tmp_list = ics; tmp_list; tmp_list = tmp_list->next)
+    set_ic_client_window (tmp_list->data, NULL);
+
+  g_slist_free (ics);
+
+  if (info->status_set)
+    g_signal_handler_disconnect (info->settings, info->status_set);
+  if (info->preedit_set)
+    g_signal_handler_disconnect (info->settings, info->preedit_set);
+  if (info->display_closed_cb)
+    g_signal_handler_disconnect (display, info->display_closed_cb);
+
+  if (info->xim_styles)
+    XFree (info->xim_styles);
+  g_free (info->locale);
+
+  if (info->im)
+    XCloseIM (info->im);
+
+  g_free (info);
+}
+
+static void
+xim_instantiate_callback (Display *display, XPointer client_data,
+                         XPointer call_data)
+{
+  GtkXIMInfo *info = (GtkXIMInfo*)client_data;
+  XIM im = NULL;
+
+  im = XOpenIM (display, NULL, NULL, NULL);
+
+  if (!im)
+    return;
+
+  info->im = im;
+  setup_im (info);
+
+  XUnregisterIMInstantiateCallback (display, NULL, NULL, NULL,
+                                   xim_instantiate_callback,
+                                   (XPointer)info);
+  info->reconnecting = FALSE;
+}
+
+/* initialize info->im */
+static void
+xim_info_try_im (GtkXIMInfo *info)
+{
+  GdkDisplay *display = info->display;
+
+  g_assert (info->im == NULL);
+  if (info->reconnecting)
+    return;
+
+  if (XSupportsLocale ())
+    {
+      if (!XSetLocaleModifiers (""))
+       g_warning ("Unable to set locale modifiers with XSetLocaleModifiers()");
+      info->im = XOpenIM (GDK_DISPLAY_XDISPLAY (display), NULL, NULL, NULL);
+      if (!info->im)
+       {
+         XRegisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY(display),
+                                         NULL, NULL, NULL,
+                                         xim_instantiate_callback,
+                                         (XPointer)info);
+         info->reconnecting = TRUE;
+         return;
+       }
+      setup_im (info);
+    }
+}
+
+static void
+xim_destroy_callback (XIM      xim,
+                     XPointer client_data,
+                     XPointer call_data)
+{
+  GtkXIMInfo *info = (GtkXIMInfo*)client_data;
+
+  info->im = NULL;
+
+  g_signal_handler_disconnect (info->settings, info->status_set);
+  info->status_set = 0;
+  g_signal_handler_disconnect (info->settings, info->preedit_set);
+  info->preedit_set = 0;
+
+  reinitialize_all_ics (info);
+  xim_info_try_im (info);
+  return;
+}
+
+static GtkXIMInfo *
+get_im (GdkWindow *client_window,
+       const char *locale)
+{
+  GSList *tmp_list;
+  GtkXIMInfo *info;
+  GdkDisplay *display = gdk_window_get_display (client_window);
+
+  info = NULL;
+  tmp_list = open_ims;
+  while (tmp_list)
+    {
+      GtkXIMInfo *tmp_info = tmp_list->data;
+      if (tmp_info->display == display &&
+         strcmp (tmp_info->locale, locale) == 0)
+       {
+         if (tmp_info->im)
+           {
+             return tmp_info;
+           }
+         else
+           {
+             tmp_info = tmp_info;
+             break;
+           }
+       }
+      tmp_list = tmp_list->next;
+    }
+
+  if (info == NULL)
+    {
+      info = g_new (GtkXIMInfo, 1);
+      open_ims = g_slist_prepend (open_ims, info);
+
+      info->display = display;
+      info->locale = g_strdup (locale);
+      info->xim_styles = NULL;
+      info->preedit_style_setting = 0;
+      info->status_style_setting = 0;
+      info->settings = NULL;
+      info->preedit_set = 0;
+      info->status_set = 0;
+      info->display_closed_cb = 0;
+      info->ics = NULL;
+      info->reconnecting = FALSE;
+      info->im = NULL;
+    }
+
+  xim_info_try_im (info);
+  return info;
+}
+
+static void
+gtk_im_context_xim_class_init (GtkIMContextXIMClass *class)
+{
+  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  im_context_class->set_client_widget = gtk_im_context_xim_set_client_widget;
+  im_context_class->filter_keypress = gtk_im_context_xim_filter_keypress;
+  im_context_class->reset = gtk_im_context_xim_reset;
+  im_context_class->get_preedit_string = gtk_im_context_xim_get_preedit_string;
+  im_context_class->focus_in = gtk_im_context_xim_focus_in;
+  im_context_class->focus_out = gtk_im_context_xim_focus_out;
+  im_context_class->set_cursor_location = gtk_im_context_xim_set_cursor_location;
+  im_context_class->set_use_preedit = gtk_im_context_xim_set_use_preedit;
+  gobject_class->finalize = gtk_im_context_xim_finalize;
+}
+
+static void
+gtk_im_context_xim_init (GtkIMContextXIM *im_context_xim)
+{
+  im_context_xim->use_preedit = TRUE;
+  im_context_xim->filter_key_release = FALSE;
+  im_context_xim->finalizing = FALSE;
+  im_context_xim->has_focus = FALSE;
+  im_context_xim->in_toplevel = FALSE;
+}
+
+static void
+gtk_im_context_xim_finalize (GObject *obj)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (obj);
+
+  context_xim->finalizing = TRUE;
+
+  if (context_xim->im_info && !context_xim->im_info->ics->next)
+    {
+      if (context_xim->im_info->reconnecting)
+       {
+         GdkDisplay *display;
+
+         display = context_xim->im_info->display;
+         XUnregisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY (display),
+                                           NULL, NULL, NULL,
+                                           xim_instantiate_callback,
+                                           (XPointer)context_xim->im_info);
+       }
+      else if (context_xim->im_info->im)
+       {
+         XIMCallback im_destroy_callback;
+
+         im_destroy_callback.client_data = NULL;
+         im_destroy_callback.callback = NULL;
+         XSetIMValues (context_xim->im_info->im,
+                       XNDestroyCallback, &im_destroy_callback,
+                       NULL);
+       }
+    }
+
+  set_ic_client_window (context_xim, NULL);
+
+  g_free (context_xim->locale);
+  g_free (context_xim->mb_charset);
+
+  G_OBJECT_CLASS (gtk_im_context_xim_parent_class)->finalize (obj);
+}
+
+static void
+reinitialize_ic (GtkIMContextXIM *context_xim)
+{
+  if (context_xim->ic)
+    {
+      XDestroyIC (context_xim->ic);
+      context_xim->ic = NULL;
+      update_status_window (context_xim);
+
+      if (context_xim->preedit_length)
+       {
+         context_xim->preedit_length = 0;
+         if (!context_xim->finalizing)
+           g_signal_emit_by_name (context_xim, "preedit-changed");
+       }
+    }
+  /*
+     reset filter_key_release flag, otherwise keystrokes will be doubled
+     until reconnecting to XIM.
+  */
+  context_xim->filter_key_release = FALSE;
+}
+
+static void
+set_ic_client_window (GtkIMContextXIM *context_xim,
+                     GdkWindow       *client_window)
+{
+  reinitialize_ic (context_xim);
+  if (context_xim->client_window)
+    {
+      context_xim->im_info->ics = g_slist_remove (context_xim->im_info->ics, context_xim);
+      context_xim->im_info = NULL;
+    }
+
+  context_xim->client_window = client_window;
+  context_xim->client_window_xid = None;
+
+  if (context_xim->client_window)
+    {
+      GdkWindow *native;
+
+      context_xim->im_info = get_im (context_xim->client_window, context_xim->locale);
+      context_xim->im_info->ics = g_slist_prepend (context_xim->im_info->ics, context_xim);
+
+      for (native = client_window; native; native = gdk_window_get_parent (native))
+        {
+          if (gdk_window_has_native (native))
+            {
+              context_xim->client_window_xid = gdk_x11_window_get_xid (native);
+              break;
+            }
+        }
+    }
+
+  update_client_widget (context_xim);
+}
+
+static void
+gtk_im_context_xim_set_client_widget (GtkIMContext *context,
+                                      GtkWidget    *widget)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+
+  set_ic_client_window (context_xim, gtk_widget_get_window (toplevel));
+}
+
+GtkIMContext *
+gtk_im_context_xim_new (void)
+{
+  GtkIMContextXIM *result;
+  const gchar *charset;
+
+  if (!GDK_IS_X11_DISPLAY(gdk_display_get_default()))
+    return NULL;
+  result = g_object_new (GTK_TYPE_IM_CONTEXT_XIM, NULL);
+
+  result->locale = g_strdup (setlocale (LC_CTYPE, NULL));
+
+  g_get_charset (&charset);
+  result->mb_charset = g_strdup (charset);
+
+  return GTK_IM_CONTEXT (result);
+}
+
+static char *
+mb_to_utf8 (GtkIMContextXIM *context_xim,
+           const char      *str)
+{
+  GError *error = NULL;
+  gchar *result;
+
+  if (strcmp (context_xim->mb_charset, "UTF-8") == 0)
+    result = g_strdup (str);
+  else
+    {
+      result = g_convert (str, -1,
+                         "UTF-8", context_xim->mb_charset,
+                         NULL, NULL, &error);
+      if (!result)
+       {
+         g_warning ("Error converting text from IM to UTF-8: %s\n", error->message);
+         g_error_free (error);
+       }
+    }
+
+  return result;
+}
+
+static gboolean
+gtk_im_context_xim_filter_keypress (GtkIMContext *context,
+                                   GdkEventKey  *event)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+  XIC ic = gtk_im_context_xim_get_ic (context_xim);
+  gchar static_buffer[256];
+  gchar *buffer = static_buffer;
+  gint buffer_size = sizeof(static_buffer) - 1;
+  gint num_bytes = 0;
+  KeySym keysym;
+  Status status;
+  gboolean result = FALSE;
+  GdkWindow *window;
+  XKeyPressedEvent xevent;
+  GdkEventType event_type;
+  guint state;
+
+  event_type = gdk_event_get_event_type ((GdkEvent *) event);
+
+  if (!gdk_event_get_state ((GdkEvent *) event, &state))
+    return GDK_EVENT_PROPAGATE;
+
+  if (event_type == GDK_KEY_RELEASE && !context_xim->filter_key_release)
+    return FALSE;
+
+  window = gdk_window_get_toplevel (gdk_event_get_window ((GdkEvent *) event));
+
+  xevent.type = (event_type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
+  xevent.serial = 0;           /* hope it doesn't matter */
+  xevent.send_event = gdk_event_is_sent ((GdkEvent *)event);
+  xevent.display = GDK_WINDOW_XDISPLAY (window);
+  xevent.window = GDK_WINDOW_XID (window);
+  xevent.root = DefaultRootWindow(GDK_WINDOW_XDISPLAY (window));
+  xevent.subwindow = xevent.window;
+  xevent.time = gdk_event_get_time ((GdkEvent *) event);
+  xevent.x = xevent.x_root = 0;
+  xevent.y = xevent.y_root = 0;
+  xevent.state = state;
+  xevent.keycode = gdk_event_get_scancode ((GdkEvent *) event);
+  xevent.same_screen = True;
+
+  if (XFilterEvent ((XEvent *)&xevent, context_xim->client_window_xid))
+    return TRUE;
+
+  if (state &
+      (gtk_accelerator_get_default_mod_mask () & ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK)))
+    return FALSE;
+
+ again:
+  if (ic)
+    num_bytes = XmbLookupString (ic, &xevent, buffer, buffer_size, &keysym, &status);
+  else
+    {
+      num_bytes = XLookupString (&xevent, buffer, buffer_size, &keysym, NULL);
+      status = XLookupBoth;
+    }
+
+  if (status == XBufferOverflow)
+    {
+      buffer_size = num_bytes;
+      if (buffer != static_buffer)
+       g_free (buffer);
+      buffer = g_malloc (num_bytes + 1);
+      goto again;
+    }
+
+  /* I don't know how we should properly handle XLookupKeysym or XLookupBoth
+   * here ... do input methods actually change the keysym? we can't really
+   * feed it back to accelerator processing at this point...
+   */
+  if (status == XLookupChars || status == XLookupBoth)
+    {
+      char *result_utf8;
+
+      buffer[num_bytes] = '\0';
+
+      result_utf8 = mb_to_utf8 (context_xim, buffer);
+      if (result_utf8)
+       {
+         if ((guchar)result_utf8[0] >= 0x20 &&
+             result_utf8[0] != 0x7f) /* Some IM have a nasty habit of converting
+                                      * control characters into strings
+                                      */
+           {
+             g_signal_emit_by_name (context, "commit", result_utf8);
+             result = TRUE;
+           }
+
+         g_free (result_utf8);
+       }
+    }
+
+  if (buffer != static_buffer)
+    g_free (buffer);
+
+  return result;
+}
+
+static void
+gtk_im_context_xim_focus_in (GtkIMContext *context)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+
+  if (!context_xim->has_focus)
+    {
+      XIC ic = gtk_im_context_xim_get_ic (context_xim);
+
+      context_xim->has_focus = TRUE;
+      update_status_window (context_xim);
+
+      if (ic)
+       XSetICFocus (ic);
+    }
+
+  return;
+}
+
+static void
+gtk_im_context_xim_focus_out (GtkIMContext *context)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+
+  if (context_xim->has_focus)
+    {
+      XIC ic = gtk_im_context_xim_get_ic (context_xim);
+
+      context_xim->has_focus = FALSE;
+      update_status_window (context_xim);
+
+      if (ic)
+       XUnsetICFocus (ic);
+    }
+
+  return;
+}
+
+static void
+gtk_im_context_xim_set_cursor_location (GtkIMContext *context,
+                                       GdkRectangle *area)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+  XIC ic = gtk_im_context_xim_get_ic (context_xim);
+
+  XVaNestedList preedit_attr;
+  XPoint          spot;
+
+  if (!ic)
+    return;
+
+  spot.x = area->x;
+  spot.y = area->y + area->height;
+
+  preedit_attr = XVaCreateNestedList (0,
+                                     XNSpotLocation, &spot,
+                                     NULL);
+  XSetICValues (ic,
+               XNPreeditAttributes, preedit_attr,
+               NULL);
+  XFree(preedit_attr);
+
+  return;
+}
+
+static void
+gtk_im_context_xim_set_use_preedit (GtkIMContext *context,
+                                   gboolean      use_preedit)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+
+  use_preedit = use_preedit != FALSE;
+
+  if (context_xim->use_preedit != use_preedit)
+    {
+      context_xim->use_preedit = use_preedit;
+      reinitialize_ic (context_xim);
+    }
+
+  return;
+}
+
+static void
+gtk_im_context_xim_reset (GtkIMContext *context)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+  XIC ic = gtk_im_context_xim_get_ic (context_xim);
+  gchar *result;
+
+  /* restore conversion state after resetting ic later */
+  XIMPreeditState preedit_state = XIMPreeditUnKnown;
+  XVaNestedList preedit_attr;
+  gboolean have_preedit_state = FALSE;
+
+  if (!ic)
+    return;
+
+
+  if (context_xim->preedit_length == 0)
+    return;
+
+  preedit_attr = XVaCreateNestedList(0,
+                                     XNPreeditState, &preedit_state,
+                                     NULL);
+  if (!XGetICValues(ic,
+                    XNPreeditAttributes, preedit_attr,
+                    NULL))
+    have_preedit_state = TRUE;
+
+  XFree(preedit_attr);
+
+  result = XmbResetIC (ic);
+
+  preedit_attr = XVaCreateNestedList(0,
+                                     XNPreeditState, preedit_state,
+                                     NULL);
+  if (have_preedit_state)
+    XSetICValues(ic,
+                XNPreeditAttributes, preedit_attr,
+                NULL);
+
+  XFree(preedit_attr);
+
+  if (result)
+    {
+      char *result_utf8 = mb_to_utf8 (context_xim, result);
+      if (result_utf8)
+       {
+         g_signal_emit_by_name (context, "commit", result_utf8);
+         g_free (result_utf8);
+       }
+    }
+
+  if (context_xim->preedit_length)
+    {
+      context_xim->preedit_length = 0;
+      g_signal_emit_by_name (context, "preedit-changed");
+    }
+
+  XFree (result);
+}
+
+/* Mask of feedback bits that we render
+ */
+#define FEEDBACK_MASK (XIMReverse | XIMUnderline)
+
+static void
+add_feedback_attr (PangoAttrList *attrs,
+                  const gchar   *str,
+                  XIMFeedback    feedback,
+                  gint           start_pos,
+                  gint           end_pos)
+{
+  PangoAttribute *attr;
+
+  gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str;
+  gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str;
+
+  if (feedback & XIMUnderline)
+    {
+      attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+      attr->start_index = start_index;
+      attr->end_index = end_index;
+
+      pango_attr_list_change (attrs, attr);
+    }
+
+  if (feedback & XIMReverse)
+    {
+      attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
+      attr->start_index = start_index;
+      attr->end_index = end_index;
+
+      pango_attr_list_change (attrs, attr);
+
+      attr = pango_attr_background_new (0, 0, 0);
+      attr->start_index = start_index;
+      attr->end_index = end_index;
+
+      pango_attr_list_change (attrs, attr);
+    }
+
+  if (feedback & ~FEEDBACK_MASK)
+    g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK);
+}
+
+static void
+gtk_im_context_xim_get_preedit_string (GtkIMContext   *context,
+                                      gchar         **str,
+                                      PangoAttrList **attrs,
+                                      gint           *cursor_pos)
+{
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+  gchar *utf8 = g_ucs4_to_utf8 (context_xim->preedit_chars, context_xim->preedit_length, NULL, NULL, NULL);
+
+  if (attrs)
+    {
+      int i;
+      XIMFeedback last_feedback = 0;
+      gint start = -1;
+
+      *attrs = pango_attr_list_new ();
+
+      for (i = 0; i < context_xim->preedit_length; i++)
+       {
+         XIMFeedback new_feedback = context_xim->feedbacks[i] & FEEDBACK_MASK;
+         if (new_feedback != last_feedback)
+           {
+             if (start >= 0)
+               add_feedback_attr (*attrs, utf8, last_feedback, start, i);
+
+             last_feedback = new_feedback;
+             start = i;
+           }
+       }
+
+      if (start >= 0)
+       add_feedback_attr (*attrs, utf8, last_feedback, start, i);
+    }
+
+  if (str)
+    *str = utf8;
+  else
+    g_free (utf8);
+
+  if (cursor_pos)
+    *cursor_pos = context_xim->preedit_cursor;
+}
+
+static int
+preedit_start_callback (XIC      xic,
+                       XPointer client_data,
+                       XPointer call_data)
+{
+  GtkIMContext *context = GTK_IM_CONTEXT (client_data);
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+
+  if (!context_xim->finalizing)
+    g_signal_emit_by_name (context, "preedit-start");
+
+  return -1;                   /* No length limit */
+}
+
+static void
+preedit_done_callback (XIC      xic,
+                    XPointer client_data,
+                    XPointer call_data)
+{
+  GtkIMContext *context = GTK_IM_CONTEXT (client_data);
+  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
+
+  if (context_xim->preedit_length)
+    {
+      context_xim->preedit_length = 0;
+      if (!context_xim->finalizing)
+       g_signal_emit_by_name (context_xim, "preedit-changed");
+    }
+
+  if (!context_xim->finalizing)
+    g_signal_emit_by_name (context, "preedit-end");
+}
+
+static gint
+xim_text_to_utf8 (GtkIMContextXIM *context, XIMText *xim_text, gchar **text)
+{
+  gint text_length = 0;
+  GError *error = NULL;
+  gchar *result = NULL;
+
+  if (xim_text && xim_text->string.multi_byte)
+    {
+      if (xim_text->encoding_is_wchar)
+       {
+         g_warning ("Wide character return from Xlib not currently supported");
+         *text = NULL;
+         return 0;
+       }
+
+      if (strcmp (context->mb_charset, "UTF-8") == 0)
+       result = g_strdup (xim_text->string.multi_byte);
+      else
+       result = g_convert (xim_text->string.multi_byte,
+                           -1,
+                           "UTF-8",
+                           context->mb_charset,
+                           NULL, NULL, &error);
+
+      if (result)
+       {
+         text_length = g_utf8_strlen (result, -1);
+
+         if (text_length != xim_text->length)
+           {
+             g_warning ("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
+           }
+       }
+      else
+       {
+         g_warning ("Error converting text from IM to UCS-4: %s", error->message);
+         g_error_free (error);
+
+         *text = NULL;
+         return 0;
+       }
+
+      *text = result;
+      return text_length;
+    }
+  else
+    {
+      *text = NULL;
+      return 0;
+    }
+}
+
+static void
+preedit_draw_callback (XIC                           xic,
+                      XPointer                      client_data,
+                      XIMPreeditDrawCallbackStruct *call_data)
+{
+  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
+
+  XIMText *new_xim_text = call_data->text;
+  gint new_text_length;
+  gunichar *new_text = NULL;
+  gint i;
+  gint diff;
+  gint new_length;
+  gchar *tmp;
+
+  gint chg_first = CLAMP (call_data->chg_first, 0, context->preedit_length);
+  gint chg_length = CLAMP (call_data->chg_length, 0, context->preedit_length - chg_first);
+
+  context->preedit_cursor = call_data->caret;
+
+  if (chg_first != call_data->chg_first || chg_length != call_data->chg_length)
+    g_warning ("Invalid change to preedit string, first=%d length=%d (orig length == %d)",
+              call_data->chg_first, call_data->chg_length, context->preedit_length);
+
+  new_text_length = xim_text_to_utf8 (context, new_xim_text, &tmp);
+  if (tmp)
+    {
+      new_text = g_utf8_to_ucs4_fast (tmp, -1, NULL);
+      g_free (tmp);
+    }
+
+  diff = new_text_length - chg_length;
+  new_length = context->preedit_length + diff;
+
+  if (new_length > context->preedit_size)
+    {
+      context->preedit_size = new_length;
+      context->preedit_chars = g_renew (gunichar, context->preedit_chars, new_length);
+      context->feedbacks = g_renew (XIMFeedback, context->feedbacks, new_length);
+    }
+
+  if (diff < 0)
+    {
+      for (i = chg_first + chg_length ; i < context->preedit_length; i++)
+       {
+         context->preedit_chars[i + diff] = context->preedit_chars[i];
+         context->feedbacks[i + diff] = context->feedbacks[i];
+       }
+    }
+  else
+    {
+      for (i = context->preedit_length - 1; i >= chg_first + chg_length ; i--)
+       {
+         context->preedit_chars[i + diff] = context->preedit_chars[i];
+         context->feedbacks[i + diff] = context->feedbacks[i];
+       }
+    }
+
+  for (i = 0; i < new_text_length; i++)
+    {
+      context->preedit_chars[chg_first + i] = new_text[i];
+      context->feedbacks[chg_first + i] = new_xim_text->feedback[i];
+    }
+
+  context->preedit_length += diff;
+
+  g_free (new_text);
+
+  if (!context->finalizing)
+    g_signal_emit_by_name (context, "preedit-changed");
+}
+
+
+static void
+preedit_caret_callback (XIC                            xic,
+                       XPointer                       client_data,
+                       XIMPreeditCaretCallbackStruct *call_data)
+{
+  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
+
+  if (call_data->direction == XIMAbsolutePosition)
+    {
+      context->preedit_cursor = call_data->position;
+      if (!context->finalizing)
+       g_signal_emit_by_name (context, "preedit-changed");
+    }
+  else
+    {
+      g_warning ("Caret movement command: %d %d %d not supported",
+                call_data->position, call_data->direction, call_data->style);
+    }
+}
+
+static void
+status_start_callback (XIC      xic,
+                      XPointer client_data,
+                      XPointer call_data)
+{
+  return;
+}
+
+static void
+status_done_callback (XIC      xic,
+                     XPointer client_data,
+                     XPointer call_data)
+{
+  return;
+}
+
+static void
+status_draw_callback (XIC      xic,
+                     XPointer client_data,
+                     XIMStatusDrawCallbackStruct *call_data)
+{
+  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
+
+  if (call_data->type == XIMTextType)
+    {
+      gchar *text;
+      xim_text_to_utf8 (context, call_data->data.text, &text);
+
+      if (context->status_window)
+       status_window_set_text (context->status_window, text ? text : "");
+    }
+  else                         /* bitmap */
+    {
+      g_print ("Status drawn with bitmap - id = %#lx\n", call_data->data.bitmap);
+    }
+}
+
+static void
+string_conversion_callback (XIC xic, XPointer client_data, XPointer call_data)
+{
+  GtkIMContextXIM *context_xim;
+  XIMStringConversionCallbackStruct *conv_data;
+  gchar *surrounding;
+  gint  cursor_index;
+
+  context_xim = (GtkIMContextXIM *)client_data;
+  conv_data = (XIMStringConversionCallbackStruct *)call_data;
+
+  if (gtk_im_context_get_surrounding ((GtkIMContext *)context_xim,
+                                      &surrounding, &cursor_index))
+    {
+      gchar *text = NULL;
+      gsize text_len = 0;
+      gint  subst_offset = 0, subst_nchars = 0;
+      gint  i;
+      gchar *p = surrounding + cursor_index, *q;
+      gshort position = (gshort)conv_data->position;
+
+      if (position > 0)
+        {
+          for (i = position; i > 0 && *p; --i)
+            p = g_utf8_next_char (p);
+          if (i > 0)
+            return;
+        }
+      /* According to X11R6.4 Xlib - C Library Reference Manual
+       * section 13.5.7.3 String Conversion Callback,
+       * XIMStringConversionPosition is starting position _relative_
+       * to current client's cursor position. So it should be able
+       * to be negative, or referring to a position before the cursor
+       * would be impossible. But current X protocol defines this as
+       * unsigned short. So, compiler may warn about the value range
+       * here. We hope the X protocol is fixed soon.
+       */
+      else if (position < 0)
+        {
+          for (i = position; i < 0 && p > surrounding; ++i)
+            p = g_utf8_prev_char (p);
+          if (i < 0)
+            return;
+        }
+
+      switch (conv_data->direction)
+        {
+        case XIMForwardChar:
+          for (i = conv_data->factor, q = p; i > 0 && *q; --i)
+            q = g_utf8_next_char (q);
+          if (i > 0)
+            break;
+          text = g_locale_from_utf8 (p, q - p, NULL, &text_len, NULL);
+          subst_offset = position;
+          subst_nchars = conv_data->factor;
+          break;
+
+        case XIMBackwardChar:
+          for (i = conv_data->factor, q = p; i > 0 && q > surrounding; --i)
+            q = g_utf8_prev_char (q);
+          if (i > 0)
+            break;
+          text = g_locale_from_utf8 (q, p - q, NULL, &text_len, NULL);
+          subst_offset = position - conv_data->factor;
+          subst_nchars = conv_data->factor;
+          break;
+
+        case XIMForwardWord:
+        case XIMBackwardWord:
+        case XIMCaretUp:
+        case XIMCaretDown:
+        case XIMNextLine:
+        case XIMPreviousLine:
+        case XIMLineStart:
+        case XIMLineEnd:
+        case XIMAbsolutePosition:
+        case XIMDontChange:
+        default:
+          break;
+        }
+      /* block out any failure happenning to "text", including conversion */
+      if (text)
+        {
+          conv_data->text = (XIMStringConversionText *)
+                              malloc (sizeof (XIMStringConversionText));
+          if (conv_data->text)
+            {
+              conv_data->text->length = text_len;
+              conv_data->text->feedback = NULL;
+              conv_data->text->encoding_is_wchar = False;
+              conv_data->text->string.mbs = (char *)malloc (text_len);
+              if (conv_data->text->string.mbs)
+                memcpy (conv_data->text->string.mbs, text, text_len);
+              else
+                {
+                  free (conv_data->text);
+                  conv_data->text = NULL;
+                }
+            }
+
+          g_free (text);
+        }
+      if (conv_data->operation == XIMStringConversionSubstitution
+          && subst_nchars > 0)
+        {
+          gtk_im_context_delete_surrounding ((GtkIMContext *)context_xim,
+                                            subst_offset, subst_nchars);
+        }
+
+      g_free (surrounding);
+    }
+}
+
+
+static XVaNestedList
+set_preedit_callback (GtkIMContextXIM *context_xim)
+{
+  context_xim->preedit_start_callback.client_data = (XPointer)context_xim;
+  context_xim->preedit_start_callback.callback = (XIMProc)preedit_start_callback;
+  context_xim->preedit_done_callback.client_data = (XPointer)context_xim;
+  context_xim->preedit_done_callback.callback = (XIMProc)preedit_done_callback;
+  context_xim->preedit_draw_callback.client_data = (XPointer)context_xim;
+  context_xim->preedit_draw_callback.callback = (XIMProc)preedit_draw_callback;
+  context_xim->preedit_caret_callback.client_data = (XPointer)context_xim;
+  context_xim->preedit_caret_callback.callback = (XIMProc)preedit_caret_callback;
+  return XVaCreateNestedList (0,
+                             XNPreeditStartCallback, &context_xim->preedit_start_callback,
+                             XNPreeditDoneCallback, &context_xim->preedit_done_callback,
+                             XNPreeditDrawCallback, &context_xim->preedit_draw_callback,
+                             XNPreeditCaretCallback, &context_xim->preedit_caret_callback,
+                             NULL);
+}
+
+static XVaNestedList
+set_status_callback (GtkIMContextXIM *context_xim)
+{
+  context_xim->status_start_callback.client_data = (XPointer)context_xim;
+  context_xim->status_start_callback.callback = (XIMProc)status_start_callback;
+  context_xim->status_done_callback.client_data = (XPointer)context_xim;
+  context_xim->status_done_callback.callback = (XIMProc)status_done_callback;
+  context_xim->status_draw_callback.client_data = (XPointer)context_xim;
+  context_xim->status_draw_callback.callback = (XIMProc)status_draw_callback;
+
+  return XVaCreateNestedList (0,
+                             XNStatusStartCallback, &context_xim->status_start_callback,
+                             XNStatusDoneCallback, &context_xim->status_done_callback,
+                             XNStatusDrawCallback, &context_xim->status_draw_callback,
+                             NULL);
+}
+
+
+static void
+set_string_conversion_callback (GtkIMContextXIM *context_xim, XIC xic)
+{
+  if (!context_xim->im_info->supports_string_conversion)
+    return;
+
+  context_xim->string_conversion_callback.client_data = (XPointer)context_xim;
+  context_xim->string_conversion_callback.callback = (XIMProc)string_conversion_callback;
+
+  XSetICValues (xic,
+               XNStringConversionCallback,
+               (XPointer)&context_xim->string_conversion_callback,
+               NULL);
+}
+
+static XIC
+gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
+{
+  if (context_xim->im_info == NULL || context_xim->im_info->im == NULL)
+    return NULL;
+
+  if (!context_xim->ic)
+    {
+      const char *name1 = NULL;
+      XVaNestedList list1 = NULL;
+      const char *name2 = NULL;
+      XVaNestedList list2 = NULL;
+      XIMStyle im_style = 0;
+      XIC xic = NULL;
+
+      if (context_xim->use_preedit &&
+         (context_xim->im_info->style & PREEDIT_MASK) == XIMPreeditCallbacks)
+       {
+         im_style |= XIMPreeditCallbacks;
+         name1 = XNPreeditAttributes;
+         list1 = set_preedit_callback (context_xim);
+       }
+      else if ((context_xim->im_info->style & PREEDIT_MASK) == XIMPreeditNone)
+       im_style |= XIMPreeditNone;
+      else
+       im_style |= XIMPreeditNothing;
+
+      if ((context_xim->im_info->style & STATUS_MASK) == XIMStatusCallbacks)
+       {
+         im_style |= XIMStatusCallbacks;
+         if (name1 == NULL)
+           {
+             name1 = XNStatusAttributes;
+             list1 = set_status_callback (context_xim);
+           }
+         else
+           {
+             name2 = XNStatusAttributes;
+             list2 = set_status_callback (context_xim);
+           }
+       }
+      else if ((context_xim->im_info->style & STATUS_MASK) == XIMStatusNone)
+       im_style |= XIMStatusNone;
+      else
+       im_style |= XIMStatusNothing;
+
+      xic = XCreateIC (context_xim->im_info->im,
+                      XNInputStyle, im_style,
+                      XNClientWindow, context_xim->client_window_xid,
+                      name1, list1,
+                      name2, list2,
+                      NULL);
+      if (list1)
+       XFree (list1);
+      if (list2)
+       XFree (list2);
+
+      if (xic)
+       {
+         /* Don't filter key released events with XFilterEvents unless
+          * input methods ask for. This is a workaround for Solaris input
+          * method bug in C and European locales. It doubles each key
+          * stroke if both key pressed and released events are filtered.
+          * (bugzilla #81759)
+          */
+         gulong mask = 0xaaaaaaaa;
+         XGetICValues (xic,
+                       XNFilterEvents, &mask,
+                       NULL);
+         context_xim->filter_key_release = (mask & KeyReleaseMask) != 0;
+         set_string_conversion_callback (context_xim, xic);
+       }
+
+      context_xim->ic = xic;
+
+      update_status_window (context_xim);
+
+      if (xic && context_xim->has_focus)
+       XSetICFocus (xic);
+    }
+  return context_xim->ic;
+}
+
+/*****************************************************************
+ * Status Window handling
+ *
+ * A status window is a small window attached to the toplevel
+ * that is used to display information to the user about the
+ * current input operation.
+ *
+ * We claim the toplevel's status window for an input context if:
+ *
+ * A) The input context has a toplevel
+ * B) The input context has the focus
+ * C) The input context has an XIC associated with it
+ *
+ * Tracking A) and C) is pretty reliable since we
+ * compute A) and create the XIC for C) ourselves.
+ * For B) we basically have to depend on our callers
+ * calling ::focus-in and ::focus-out at the right time.
+ *
+ * The toplevel is computed by walking up the GdkWindow
+ * hierarchy from context->client_window until we find a
+ * window that is owned by some widget, and then calling
+ * gtk_widget_get_toplevel() on that widget. This should
+ * handle both cases where we might have GdkWindows without widgets,
+ * and cases where GtkWidgets have strange window hierarchies
+ * (like a torn off GtkHandleBox.)
+ *
+ * The status window is visible if and only if there is text
+ * for it; whenever a new GtkIMContextXIM claims the status
+ * window, we blank out any existing text. We actually only
+ * create a GtkWindow for the status window the first time
+ * it is shown; this is an important optimization when we are
+ * using XIM with something like a simple compose-key input
+ * method that never needs a status window.
+ *****************************************************************/
+
+/* Called when we no longer need a status window
+*/
+static void
+disclaim_status_window (GtkIMContextXIM *context_xim)
+{
+  if (context_xim->status_window)
+    {
+      g_assert (context_xim->status_window->context == context_xim);
+
+      status_window_set_text (context_xim->status_window, "");
+
+      context_xim->status_window->context = NULL;
+      context_xim->status_window = NULL;
+    }
+}
+
+/* Called when we need a status window
+ */
+static void
+claim_status_window (GtkIMContextXIM *context_xim)
+{
+  if (!context_xim->status_window && context_xim->client_widget)
+    {
+      GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
+      if (toplevel && gtk_widget_is_toplevel (toplevel))
+       {
+         StatusWindow *status_window = status_window_get (toplevel);
+
+         if (status_window->context)
+           disclaim_status_window (status_window->context);
+
+         status_window->context = context_xim;
+         context_xim->status_window = status_window;
+       }
+    }
+}
+
+/* Basic call made whenever something changed that might cause
+ * us to need, or not to need a status window.
+ */
+static void
+update_status_window (GtkIMContextXIM *context_xim)
+{
+  if (context_xim->ic && context_xim->in_toplevel && context_xim->has_focus)
+    claim_status_window (context_xim);
+  else
+    disclaim_status_window (context_xim);
+}
+
+/* Updates the in_toplevel flag for @context_xim
+ */
+static void
+update_in_toplevel (GtkIMContextXIM *context_xim)
+{
+  if (context_xim->client_widget)
+    {
+      GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
+
+      context_xim->in_toplevel = (toplevel && gtk_widget_is_toplevel (toplevel));
+    }
+  else
+    context_xim->in_toplevel = FALSE;
+
+  /* Some paranoia, in case we don't get a focus out */
+  if (!context_xim->in_toplevel)
+    context_xim->has_focus = FALSE;
+
+  update_status_window (context_xim);
+}
+
+/* Callback when @widget's toplevel changes. It will always
+ * change from NULL to a window, or a window to NULL;
+ * we use that intermediate NULL state to make sure
+ * that we disclaim the toplevel status window for the old
+ * window.
+ */
+static void
+on_client_widget_hierarchy_changed (GtkWidget       *widget,
+                                   GtkWidget       *old_toplevel,
+                                   GtkIMContextXIM *context_xim)
+{
+  update_in_toplevel (context_xim);
+}
+
+/* Finds the GtkWidget that owns the window, or if none, the
+ * widget owning the nearest parent that has a widget.
+ */
+static GtkWidget *
+widget_for_window (GdkWindow *window)
+{
+  while (window)
+    {
+      gpointer user_data;
+      gdk_window_get_user_data (window, &user_data);
+      if (user_data)
+       return user_data;
+
+      window = gdk_window_get_parent (window);
+    }
+
+  return NULL;
+}
+
+/* Called when context_xim->client_window changes; takes care of
+ * removing and/or setting up our watches for the toplevel
+ */
+static void
+update_client_widget (GtkIMContextXIM *context_xim)
+{
+  GtkWidget *new_client_widget = widget_for_window (context_xim->client_window);
+
+  if (new_client_widget != context_xim->client_widget)
+    {
+      if (context_xim->client_widget)
+       {
+         g_signal_handlers_disconnect_by_func (context_xim->client_widget,
+                                               G_CALLBACK (on_client_widget_hierarchy_changed),
+                                               context_xim);
+       }
+      context_xim->client_widget = new_client_widget;
+      if (context_xim->client_widget)
+       {
+         g_signal_connect (context_xim->client_widget, "hierarchy-changed",
+                           G_CALLBACK (on_client_widget_hierarchy_changed),
+                           context_xim);
+       }
+
+      update_in_toplevel (context_xim);
+    }
+}
+
+/* Called when the toplevel is destroyed; frees the status window
+ */
+static void
+on_status_toplevel_destroy (GtkWidget    *toplevel,
+                           StatusWindow *status_window)
+{
+  status_window_free (status_window);
+}
+
+/* Called when the screen for the toplevel changes; updates the
+ * screen for the status window to match.
+ */
+static void
+on_status_toplevel_notify_display (GtkWindow    *toplevel,
+                                  GParamSpec   *pspec,
+                                  StatusWindow *status_window)
+{
+  if (status_window->window)
+    gtk_window_set_display (GTK_WINDOW (status_window->window),
+                           gtk_widget_get_display (GTK_WIDGET (toplevel)));
+}
+
+/* Called when the toplevel window is moved; updates the position of
+ * the status window to follow it.
+ */
+static gboolean
+on_status_toplevel_configure (GtkWidget     *toplevel,
+                             GdkEvent      *event,
+                             StatusWindow  *status_window)
+{
+  if (gdk_event_get_event_type (event) == GDK_CONFIGURE)
+    {
+      GdkRectangle rect;
+      GtkRequisition requisition;
+      gint y;
+      gint height;
+
+      if (status_window->window)
+        {
+          height = DisplayHeight(GDK_WINDOW_XDISPLAY (gtk_widget_get_window (toplevel)), 0);
+
+          gdk_window_get_frame_extents (gtk_widget_get_window (toplevel), &rect);
+          gtk_widget_get_preferred_size ( (status_window->window), &requisition, NULL);
+
+          if (rect.y + rect.height + requisition.height < height)
+           y = rect.y + rect.height;
+          else
+           y = height - requisition.height;
+
+          gtk_window_move (GTK_WINDOW (status_window->window), rect.x, y);
+        }
+    }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+/* Frees a status window and removes its link from the status_windows list
+ */
+static void
+status_window_free (StatusWindow *status_window)
+{
+  status_windows = g_slist_remove (status_windows, status_window);
+
+  if (status_window->context)
+    status_window->context->status_window = NULL;
+
+  g_signal_handlers_disconnect_by_func (status_window->toplevel,
+                                       G_CALLBACK (on_status_toplevel_destroy),
+                                       status_window);
+  g_signal_handlers_disconnect_by_func (status_window->toplevel,
+                                       G_CALLBACK (on_status_toplevel_notify_display),
+                                       status_window);
+  g_signal_handlers_disconnect_by_func (status_window->toplevel,
+                                       G_CALLBACK (on_status_toplevel_configure),
+                                       status_window);
+
+  if (status_window->window)
+    gtk_widget_destroy (status_window->window);
+
+  g_object_set_data (G_OBJECT (status_window->toplevel), "gtk-im-xim-status-window", NULL);
+
+  g_free (status_window);
+}
+
+/* Finds the status window object for a toplevel, creating it if necessary.
+ */
+static StatusWindow *
+status_window_get (GtkWidget *toplevel)
+{
+  StatusWindow *status_window;
+
+  status_window = g_object_get_data (G_OBJECT (toplevel), "gtk-im-xim-status-window");
+  if (status_window)
+    return status_window;
+
+  status_window = g_new0 (StatusWindow, 1);
+  status_window->toplevel = toplevel;
+
+  status_windows = g_slist_prepend (status_windows, status_window);
+
+  g_signal_connect (toplevel, "destroy",
+                   G_CALLBACK (on_status_toplevel_destroy),
+                   status_window);
+  g_signal_connect (toplevel, "event",
+                   G_CALLBACK (on_status_toplevel_configure),
+                   status_window);
+  g_signal_connect (toplevel, "notify::display",
+                   G_CALLBACK (on_status_toplevel_notify_display),
+                   status_window);
+
+  g_object_set_data (G_OBJECT (toplevel), "gtk-im-xim-status-window", status_window);
+
+  return status_window;
+}
+
+/* Creates the widgets for the status window; called when we
+ * first need to show text for the status window.
+ */
+static void
+status_window_make_window (StatusWindow *status_window)
+{
+  GtkWidget *window;
+  GtkWidget *status_label;
+
+  status_window->window = gtk_window_new (GTK_WINDOW_POPUP);
+  window = status_window->window;
+
+  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+
+  status_label = gtk_label_new ("");
+  g_object_set (status_label, "margin", 1, NULL);
+  gtk_widget_show (status_label);
+
+  gtk_container_add (GTK_CONTAINER (window), status_label);
+
+  gtk_window_set_display (GTK_WINDOW (status_window->window),
+                         gtk_widget_get_display (status_window->toplevel));
+
+  on_status_toplevel_configure (status_window->toplevel, NULL, status_window);
+}
+
+/* Updates the text in the status window, hiding or
+ * showing the window as necessary.
+ */
+static void
+status_window_set_text (StatusWindow *status_window,
+                       const gchar  *text)
+{
+  if (text[0])
+    {
+      GtkWidget *label;
+
+      if (!status_window->window)
+       status_window_make_window (status_window);
+
+      label = gtk_bin_get_child (GTK_BIN (status_window->window));
+      gtk_label_set_text (GTK_LABEL (label), text);
+
+      gtk_widget_show (status_window->window);
+    }
+  else
+    {
+      if (status_window->window)
+       gtk_widget_hide (status_window->window);
+    }
+}
+
+/**
+ * gtk_im_context_xim_shutdown:
+ *
+ * Destroys all the status windows that are kept by the XIM contexts.  This
+ * function should only be called by the XIM module exit routine.
+ **/
+void
+gtk_im_context_xim_shutdown (void)
+{
+  while (status_windows)
+    status_window_free (status_windows->data);
+
+  while (open_ims)
+    {
+      GtkXIMInfo *info = open_ims->data;
+      GdkDisplay *display = info->display;
+
+      xim_info_display_closed (display, FALSE, info);
+      open_ims = g_slist_remove_link (open_ims, open_ims);
+    }
+}
diff --git a/gtk/gtkimcontextxim.h b/gtk/gtkimcontextxim.h
new file mode 100644 (file)
index 0000000..5965c65
--- /dev/null
@@ -0,0 +1,48 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_IM_CONTEXT_XIM_H__
+#define __GTK_IM_CONTEXT_XIM_H__
+
+#include <gtk/gtk.h>
+#include "x11/gdkx.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_IM_CONTEXT_XIM            (gtk_im_context_xim_get_type ())
+#define GTK_IM_CONTEXT_XIM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIM))
+#define GTK_IM_CONTEXT_XIM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))
+#define GTK_IS_IM_CONTEXT_XIM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_IM_CONTEXT_XIM))
+#define GTK_IS_IM_CONTEXT_XIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IM_CONTEXT_XIM))
+#define GTK_IM_CONTEXT_XIM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))
+
+
+typedef struct _GtkIMContextXIM       GtkIMContextXIM;
+typedef struct _GtkIMContextXIMClass  GtkIMContextXIMClass;
+
+struct _GtkIMContextXIMClass
+{
+  GtkIMContextClass parent_class;
+};
+
+GType         gtk_im_context_xim_get_type (void) G_GNUC_CONST;
+GtkIMContext *gtk_im_context_xim_new      (void);
+void          gtk_im_context_xim_shutdown (void);
+
+G_END_DECLS
+
+#endif /* __GTK_IM_CONTEXT_XIM_H__ */
index 021b5c10b50f87dd33d4cce485fdc894239531ba..5e45bd8cfb3f4142072210ff7b4d083dd5e21ac9 100644 (file)
 
 #ifdef GDK_WINDOWING_X11
 #include "x11/gdkx.h"
+#include "gtkimcontextxim.h"
 #endif
 
 #ifdef GDK_WINDOWING_WAYLAND
 #include "wayland/gdkwayland.h"
+#include "gtkimcontextwayland.h"
 #endif
 
 #ifdef GDK_WINDOWING_BROADWAY
 #include "broadway/gdkbroadway.h"
+#include "gtkimcontextbroadway.h"
 #endif
 
 #ifdef GDK_WINDOWING_WIN32
 #include "win32/gdkwin32.h"
+#include "gtkimcontextime.h"
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+#include "quartz/gdkquartz.h"
+#include "gtkimcontextquartz.h"
 #endif
 
 #ifdef G_OS_WIN32
@@ -101,6 +110,7 @@ is_platform (const char *context_id)
   return g_strcmp0 (context_id, "wayland") == 0 ||
          g_strcmp0 (context_id, "broadway") == 0 ||
          g_strcmp0 (context_id, "xim") == 0 ||
+         g_strcmp0 (context_id, "quartz") == 0 ||
          g_strcmp0 (context_id, "ime") == 0;
 }
 
@@ -127,6 +137,11 @@ match_backend (const char *context_id)
     return GDK_IS_WIN32_DISPLAY (gdk_display_get_default ());
 #endif
 
+#ifdef GDK_WINDOWING_QUARTZ
+  if (g_strcmp0 (context_id, "quartz") == 0)
+    return GDK_IS_QUARTZ_DISPLAY (gdk_display_get_default ());
+#endif
+
   return TRUE;
 }
 
@@ -236,7 +251,21 @@ gtk_im_modules_init (void)
   g_io_extension_point_set_required_type (ep, GTK_TYPE_IM_CONTEXT);
 
   g_type_ensure (gtk_im_context_simple_get_type ());
-  // other builtin im context types go here
+#ifdef GDK_WINDOWING_X11
+  g_type_ensure (gtk_im_context_xim_get_type ());
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+  g_type_ensure (gtk_im_context_wayland_get_type ());
+#endif
+#ifdef GDK_WINDOWING_BROADWAY
+  g_type_ensure (gtk_im_context_broadway_get_type ());
+#endif
+#ifdef GDK_WINDOWING_WIN32
+  g_type_ensure (gtk_im_context_ime_get_type ());
+#endif
+#ifdef GDK_WINDOWING_QUARTZ
+  g_type_ensure (gtk_im_context_quartz_get_type ());
+#endif
 
   scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
 
@@ -251,16 +280,17 @@ gtk_im_modules_init (void)
 
   g_io_module_scope_free (scope);
 
-  {
-    GList *list, *l;
-
-    list = g_io_extension_point_get_extensions (ep);
-    for (l = list; l; l = l->next)
-      {
-        GIOExtension *ext = l->data;
-        g_print ("extension: %s: type %s\n",
-                 g_io_extension_get_name (ext),
-                 g_type_name (g_io_extension_get_type (ext)));
-      }
-  }
+  if (GTK_DEBUG_CHECK (MODULES))
+    {
+      GList *list, *l;
+
+      list = g_io_extension_point_get_extensions (ep);
+      for (l = list; l; l = l->next)
+        {
+          GIOExtension *ext = l->data;
+          g_print ("extension: %s: type %s\n",
+                   g_io_extension_get_name (ext),
+                   g_type_name (g_io_extension_get_type (ext)));
+        }
+    }
 }
diff --git a/gtk/imm-extra.h b/gtk/imm-extra.h
new file mode 100644 (file)
index 0000000..094dc5b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2003 Takuro Ashie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * $Id$ 
+ */
+
+#include <windows.h>
+#include <imm.h>
+
+
+/* these aren't defined in Cygwin's imm.h */
+
+#ifndef WM_IME_REQUEST
+#   define WM_IME_REQUEST                  0x0288
+#endif  /* WM_IME_REQUEST */
+
+#ifndef IMR_COMPOSITIONWINDOW
+#   define IMR_COMPOSITIONWINDOW           0x0001
+#endif /* IMR_COMPOSITIONWINDOW */
+
+#ifndef IMR_CANDIDATEWINDOW
+#   define IMR_CANDIDATEWINDOW             0x0002
+#endif /* IMR_CANDIDATEWINDOW */
+
+#ifndef IMR_COMPOSITIONFONT
+#   define IMR_COMPOSITIONFONT             0x0003
+#endif /* IMR_COMPOSITIONFONT */
+
+#ifndef IMR_RECONVERTSTRING
+#   define IMR_RECONVERTSTRING             0x0004
+#endif /* IMR_RECONVERTSTRING */
+
+#ifndef IMR_CONFIRMRECONVERTSTRING
+#   define IMR_CONFIRMRECONVERTSTRING      0x0005
+#endif /* IMR_CONFIRMRECONVERTSTRING */
+
+#ifndef IMR_QUERYCHARPOSITION
+#   define IMR_QUERYCHARPOSITION           0x0006
+typedef struct tagIMECHARPOSITION {
+  DWORD  dwSize;
+  DWORD  dwCharPos;
+  POINT  pt;
+  UINT   cLineHeight;
+  RECT   rcDocument;
+} IMECHARPOSITION, *PIMECHARPOSITION;
+#endif /* IMR_QUERYCHARPOSITION */
+
+#ifndef IMR_DOCUMENTFEED
+#   define IMR_DOCUMENTFEED                0x0007
+#endif /* IMR_DOCUMENTFEED */
index 58af3bebbfb9e5855ec14e8666d8efd823216b41..43e3c1daaaa211080fe5a51e2a926b80da3222f1 100644 (file)
@@ -578,6 +578,48 @@ install_headers(gtk_public_headers, subdir: 'gtk-4.0/gtk/')
 
 gtk_sources = gtk_public_sources + gtk_private_sources
 
+proto_sources = [
+  ['gtk-text-input', 'stable', ],
+]
+
+im_wayland_sources = files('gtkimcontextwayland.c')
+wayland_scanner = find_program('wayland-scanner')
+genprotocols = find_program('../gdk/wayland/genprotocolfiles.py')
+
+foreach p: proto_sources
+  proto_name = p.get(0)
+  proto_stability = p.get(1)
+
+  if proto_stability == 'stable'
+    output_base = proto_name
+    input = '@0@.xml'.format(proto_name)
+  else
+    proto_version = p.get(2)
+    output_base = '@0@-@1@-@2@'.format(proto_name, proto_stability, proto_version)
+    input = join_paths(proto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
+  endif
+
+  im_wayland_sources += custom_target('@0@ client header'.format(output_base),
+                                      input: input,
+                                      output: '@0@-client-protocol.h'.format(output_base),
+                                      command: [
+                                        genprotocols,
+                                        wayland_scanner,
+                                        '@INPUT@', '@OUTPUT@',
+                                        'client-header',
+                                      ])
+
+  im_wayland_sources += custom_target('@0@ source'.format(output_base),
+                                      input: input,
+                                      output: '@0@-protocol.c'.format(output_base),
+                                      command: [
+                                        genprotocols,
+                                        wayland_scanner,
+                                        '@INPUT@', '@OUTPUT@',
+                                        'code',
+                                      ])
+endforeach
+
 if os_unix
   gtk_unix_print_headers = [
     'gtkpagesetupunixdialog.h',
@@ -616,6 +658,7 @@ if os_win32
   ])
 
   gtk_sources += gtk_win32_print_sources
+  gtk_sources += ['gtkimcontextime.c']
 
   if cc.has_header_symbol('windows.h', 'IPrintDialogCallback')
     cdata.set('HAVE_IPRINTDIALOGCALLBACK', 1)
@@ -624,10 +667,12 @@ endif
 
 if x11_enabled
   gtk_sources += ['gtkapplication-x11.c', 'gtkmountoperation-x11.c']
+  gtk_sources += ['gtkimcontextxim.c']
 endif
 
 if wayland_enabled
   gtk_sources += ['gtkapplication-wayland.c']
+  gtk_sources += im_wayland_sources
 endif
 
 if x11_enabled or wayland_enabled
@@ -647,6 +692,8 @@ if quartz_enabled
     'gtkfilechoosernativequartz.c',
     'gtkquartz.c',
   ])
+  gtk_sources += ['gtkimcontextquartz.c']
+
   gtk_cargs += ['-xobjective-c']  # FIXME? maybe add_languages() instead?
 endif
 
@@ -824,6 +871,10 @@ if wayland_enabled
   gtk_sources += gtk_wayland_sources
 endif
 
+if broadway_enabled
+  gtk_sources += ['gtkimcontextbroadway.c']
+endif
+
 if win32_enabled
   gtk_cargs += ['-DGTK_PRINT_BACKENDS="file,lpr"']
   gtk_deps += [ giowin32_dep ]
@@ -868,39 +919,6 @@ if cc.has_header('langinfo.h')
   endforeach
 endif
 
-# Input methods
-
-gen_headers = [ gtk_gen_headers, gsk_gen_headers, gdk_gen_headers, ]
-
-included_input_modules = []
-foreach m: inc_im_method_defs       # populated in modules/input/meson.build
-  im_name = m[0]
-  im_srcs = m[1]
-  im_args = m[2]
-  im_libs = m[3]
-
-  included_input_modules += static_library('im-@0@'.format(im_name),
-                                           im_srcs, gen_headers,
-                                           c_args: im_args,
-                                           include_directories: [confinc, gdkinc, gtkinc],
-                                           dependencies: gtk_deps + im_libs)
-endforeach
-
-foreach m: dyn_im_method_defs       # populated in modules/input/meson.build
-  im_name = m[0]
-  im_srcs = m[1]
-  im_args = m[2]
-  im_libs = m[3]
-
-  shared_module('libim-@0@'.format(im_name), im_srcs, gen_headers,
-                c_args: im_args,
-                include_directories: [confinc, gdkinc, gtkinc],
-                dependencies: gtk_deps + im_libs,
-                name_prefix: '', # we want im-foo.so not libim-foo.so
-                install_dir: immodules_install_dir,
-                install: true)
-endforeach
-
 # Library
 libgtk = shared_library('gtk-4',
                         soversion: gtk_soversion,
@@ -909,7 +927,6 @@ libgtk = shared_library('gtk-4',
                         include_directories: [confinc, gdkinc, gskinc, gtkinc],
                         dependencies: gtk_deps + [libgdk_dep, libgsk_dep],
                         link_with: [libgdk, libgsk, ],
-                        link_whole: included_input_modules,
                         link_args: common_ldflags,
                         install: true)
 
index b778b5fa8e53bec5203bc8751e08ca65b0c03626..d50d2f222e446ead36d8d8ec05e8a999c8576bdb 100644 (file)
@@ -589,7 +589,6 @@ if cloudproviders_enabled
   endif
 endif
 
-subdir('modules/input')
 subdir('gdk')
 subdir('gsk')
 subdir('gtk')
index 0c34a1fdbb642e7db6bfc99f5225f8a615917755..74e5f21b3273d284ede37e2a9357debb2b57c58b 100644 (file)
@@ -24,12 +24,6 @@ option('print-backends', type : 'string', value : 'cups,file',
 option('colord', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto',
   description : 'Build colord support for the CUPS printing backend')
 
-# Modules
-option('dynamic-modules', type: 'boolean', value : true,
-  description : 'Allow dynamic module loading')
-option('included-immodules', type: 'string', value : 'none',
-  description : 'Build the specified input methods (comma-separated list, "all", or "none")')
-
 # Documentation and introspection
 option('documentation', type: 'boolean', value: 'false',
   description : 'Build API reference and tools documentation')
diff --git a/modules/input/gtk-text-input.xml b/modules/input/gtk-text-input.xml
deleted file mode 100644 (file)
index a134a19..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<protocol name="gtk_text_input">
-  <copyright>
-    Copyright © 2012, 2013 Intel Corporation
-    Copyright © 2015, 2016 Jan Arne Petersen
-
-    Permission to use, copy, modify, distribute, and sell this
-    software and its documentation for any purpose is hereby granted
-    without fee, provided that the above copyright notice appear in
-    all copies and that both that copyright notice and this permission
-    notice appear in supporting documentation, and that the name of
-    the copyright holders not be used in advertising or publicity
-    pertaining to distribution of the software without specific,
-    written prior permission.  The copyright holders make no
-    representations about the suitability of this software for any
-    purpose.  It is provided "as is" without express or implied
-    warranty.
-
-    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
-    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
-    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
-    THIS SOFTWARE.
-  </copyright>
-
-  <interface name="gtk_text_input" version="1">
-    <description summary="text input">
-      The gtk_text_input interface represents text input and input methods
-      associated with a seat. It provides enter/leave events to follow the
-      text input focus for a seat.
-
-      Requests are used to enable/disable the text-input object and set
-      state information like surrounding and selected text or the content type.
-      The information about the entered text is sent to the text-input object
-      via the pre-edit and commit_string events. Using this interface removes
-      the need for applications to directly process hardware key events and
-      compose text out of them.
-
-      Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
-      have to always point to the first byte of an UTF-8 encoded code point.
-      Lengths are not allowed to contain just a part of an UTF-8 encoded code
-      point.
-
-      Focus moving throughout surfaces will result in the emission of
-      gtk_text_input.enter and gtk_text_input.leave events. The focused
-      surface must perform gtk_text_input.enable and
-      gtk_text_input.disable requests as the keyboard focus moves across
-      editable and non-editable elements of the UI. Those two requests are not
-      expected to be paired with each other, the compositor must be able to
-      handle consecutive series of the same request.
-
-      State is sent by the state requests (set_surrounding_text,
-      set_content_type and set_cursor_rectangle) and a commit request.
-      After an enter event or disable request all state information is
-      invalidated and needs to be resent by the client.
-
-      This protocol defines requests and events necessary for regular clients
-      to communicate with an input method. The gtk_input_method protocol
-      defines the interfaces necessary to implement standalone input methods.
-      If a compositor implements both interfaces, it will be the arbiter of the
-      communication between both.
-
-      Warning! The protocol described in this file is experimental and
-      backward incompatible changes may be made. Backward compatible changes
-      may be added together with the corresponding interface version bump.
-      Backward incompatible changes are done by bumping the version number in
-      the protocol and interface names and resetting the interface version.
-      Once the protocol is to be declared stable, the 'z' prefix and the
-      version number in the protocol and interface names are removed and the
-      interface version number is reset.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="Destroy the wp_text_input">
-       Destroy the wp_text_input object. Also disables all surfaces enabled
-       through this wp_text_input object
-      </description>
-    </request>
-
-    <enum name="enable_flags" bitfield="true">
-      <description summary="enable flags">
-       Content hint is a bitmask to allow to modify the behavior of the text
-       input.
-      </description>
-      <entry name="none" value="0x0" summary="no special behaviour"/>
-      <entry name="can_show_preedit" value="0x1" summary="hints that the UI is capable of showing pre-edit text"/>
-      <entry name="toggle_input_panel" value="0x2" summary="requests toggling input panel (eg. on-screen keyboard)"/>
-    </enum>
-
-    <request name="enable">
-      <description summary="Request text input to be enabled">
-       Requests text input on a surface. The serial provided must be the one
-        received on gtk_text_input.enter.
-      </description>
-      <arg name="serial" type="uint" summary="serial of enter event"/>
-      <arg name="show_input_panel" type="uint" summary="details of the enable request"/>
-    </request>
-
-    <request name="disable">
-      <description summary="Disable text input on a surface">
-       Explicitly disable text input in a surface (typically when there is no
-       focus on any text entry inside the surface).
-      </description>
-    </request>
-
-    <request name="set_surrounding_text">
-      <description summary="sets the surrounding text">
-       Sets the plain surrounding text around the input position. Text is
-       UTF-8 encoded. Cursor is the byte offset within the surrounding text.
-       Anchor is the byte offset of the selection anchor within the
-       surrounding text. If there is no selected text, anchor is the same as
-       cursor.
-
-       Make sure to always send some text before and after the cursor
-       except when the cursor is at the beginning or end of text.
-
-       When there was a configure_surrounding_text event take the
-       before_cursor and after_cursor arguments into account for picking how
-       much surrounding text to send.
-
-       There is a maximum length of wayland messages so text can not be
-       longer than 4000 bytes.
-      </description>
-      <arg name="text" type="string"/>
-      <arg name="cursor" type="int"/>
-      <arg name="anchor" type="int"/>
-    </request>
-
-    <enum name="content_hint" bitfield="true">
-      <description summary="content hint">
-       Content hint is a bitmask to allow to modify the behavior of the text
-       input.
-      </description>
-      <entry name="none" value="0x0" summary="no special behaviour"/>
-      <entry name="completion" value="0x1" summary="suggest word completions"/>
-      <entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
-      <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
-      <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
-      <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
-      <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
-      <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
-      <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
-      <entry name="latin" value="0x100" summary="just latin characters should be entered"/>
-      <entry name="multiline" value="0x200" summary="the text input is multiline"/>
-    </enum>
-
-    <enum name="content_purpose">
-      <description summary="content purpose">
-       The content purpose allows to specify the primary purpose of a text
-       input.
-
-       This allows an input method to show special purpose input panels with
-       extra characters or to disallow some characters.
-      </description>
-      <entry name="normal" value="0" summary="default input, allowing all characters"/>
-      <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
-      <entry name="digits" value="2" summary="allow only digits"/>
-      <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
-      <entry name="phone" value="4" summary="input a phone number"/>
-      <entry name="url" value="5" summary="input an URL"/>
-      <entry name="email" value="6" summary="input an email address"/>
-      <entry name="name" value="7" summary="input a name of a person"/>
-      <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/>
-      <entry name="pin" value="9" summary="input is a numeric password (combine with password or sensitive_data hint)"/>
-      <entry name="date" value="10" summary="input a date"/>
-      <entry name="time" value="11" summary="input a time"/>
-      <entry name="datetime" value="12" summary="input a date and time"/>
-      <entry name="terminal" value="13" summary="input for a terminal"/>
-    </enum>
-
-    <request name="set_content_type">
-      <description summary="set content purpose and hint">
-       Sets the content purpose and content hint. While the purpose is the
-       basic purpose of an input field, the hint flags allow to modify some
-       of the behavior.
-
-       When no content type is explicitly set, a normal content purpose with
-       none hint should be assumed.
-      </description>
-      <arg name="hint" type="uint" enum="content_hint"/>
-      <arg name="purpose" type="uint" enum="content_purpose"/>
-    </request>
-
-    <request name="set_cursor_rectangle">
-      <description summary="set cursor position">
-       Sets the cursor outline as a x, y, width, height rectangle in surface
-       local coordinates.
-
-       Allows the compositor to put a window with word suggestions near the
-       cursor.
-      </description>
-      <arg name="x" type="int"/>
-      <arg name="y" type="int"/>
-      <arg name="width" type="int"/>
-      <arg name="height" type="int"/>
-    </request>
-
-    <request name="commit">
-      <description summary="commit state">
-       Allows to atomically send state updates from client. The previous
-       set_surrounding_text, set_content_type and set_cursor_rectangle
-       become effective after this call.
-
-       Serial should be set to the serial from the last wp_text_input.enter
-       event.
-
-       To make sure to not receive outdated input method events after a
-       state update, wl_display_sync() should be called after making this
-       request.
-      </description>
-    </request>
-
-    <event name="enter">
-      <description summary="enter event">
-       Notification that this seat's text-input focus is on a certain surface.
-
-       When the seat has the keyboard capability the text-input focus follows
-       the keyboard focus.
-      </description>
-      <arg name="serial" type="uint" summary="serial"/>
-      <arg name="surface" type="object" interface="wl_surface"/>
-    </event>
-
-    <event name="leave">
-      <description summary="leave event">
-       Notification that this seat's text-input focus is no longer on
-       a certain surface. The client should reset any preedit string previously
-       set.
-
-       The leave notification is sent before the enter notification
-       for the new focus.
-
-       When the seat has the keyboard capability the text-input focus follows
-       the keyboard focus.
-      </description>
-      <arg name="serial" type="uint"/>
-      <arg name="surface" type="object" interface="wl_surface"/>
-    </event>
-
-    <event name="preedit_string">
-      <description summary="pre-edit">
-       Notify when a new composing text (pre-edit) should be set around the
-       current cursor position. Any previously set composing text should
-       be removed.
-      </description>
-      <arg name="text" type="string" allow-null="true"/>
-      <arg name="cursor" type="uint"/>
-    </event>
-
-    <event name="commit_string">
-      <description summary="text commit">
-       Notify when text should be inserted into the editor widget. The text to
-       commit could be either just a single character after a key press or the
-       result of some composing (pre-edit).
-
-       The text argument could be also null if some text is removed (see
-       gtk_text_input.delete_surrounding_text).
-
-       Any previously set composing text should be removed.
-      </description>
-      <arg name="text" type="string" allow-null="true"/>
-    </event>
-
-    <event name="delete_surrounding_text">
-      <description summary="delete surrounding text">
-       Notify when the text around the current cursor position should be
-       deleted. Before_length and after_length is the length (in bytes) of text
-       before and after the current cursor position (excluding the selection)
-       to delete.
-
-       This event should be handled as part of a following commit_string or
-       preedit_string event.
-      </description>
-      <arg name="before_length" type="uint" summary="length of text before current cursor position"/>
-      <arg name="after_length" type="uint" summary="length of text after current cursor position"/>
-    </event>
-  </interface>
-
-  <interface name="gtk_text_input_manager" version="1">
-    <description summary="text input manager">
-      A factory for text-input objects. This object is a global singleton.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="Destroy the wp_text_input_manager">
-       Destroy the wp_text_input_manager object.
-      </description>
-    </request>
-
-    <request name="get_text_input">
-      <description summary="create a new text input object">
-       Creates a new text-input object for a given seat.
-      </description>
-      <arg name="id" type="new_id" interface="gtk_text_input"/>
-      <arg name="seat" type="object" interface="wl_seat"/>
-    </request>
-  </interface>
-</protocol>
diff --git a/modules/input/gtkimcontextime.c b/modules/input/gtkimcontextime.c
deleted file mode 100644 (file)
index 212a17b..0000000
+++ /dev/null
@@ -1,1221 +0,0 @@
-/*
- * gtkimcontextime.c
- * Copyright (C) 2003 Takuro Ashie
- * Copyright (C) 2003-2004 Kazuki IWAMOTO
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/*
- *  Please see the following site for the detail of Windows IME API.
- *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/appendix/hh/appendix/imeimes2_35ph.asp
- */
-
-#ifdef GTK_DISABLE_DEPRECATED
-#undef GTK_DISABLE_DEPRECATED
-#endif
-
-#include "gtkimcontextime.h"
-
-#include "imm-extra.h"
-
-#include "gdk/gdkkeysyms.h"
-#include "gdk/win32/gdkwin32.h"
-#include "gdk/gdkkeysyms.h"
-
-#include <pango/pango.h>
-
-/* avoid warning */
-#ifdef STRICT
-# undef STRICT
-# include <pango/pangowin32.h>
-# ifndef STRICT
-#   define STRICT 1
-# endif
-#else /* STRICT */
-#   include <pango/pangowin32.h>
-#endif /* STRICT */
-
-/* #define BUFSIZE 4096 */
-
-#define IS_DEAD_KEY(k) \
-    ((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
-
-#define FREE_PREEDIT_BUFFER(ctx) \
-{                                \
-  g_free((ctx)->priv->comp_str); \
-  g_free((ctx)->priv->read_str); \
-  (ctx)->priv->comp_str = NULL;  \
-  (ctx)->priv->read_str = NULL;  \
-  (ctx)->priv->comp_str_len = 0; \
-  (ctx)->priv->read_str_len = 0; \
-}
-
-
-struct _GtkIMContextIMEPrivate
-{
-  /* save IME context when the client window is focused out */
-  DWORD conversion_mode;
-  DWORD sentence_mode;
-
-  LPVOID comp_str;
-  DWORD comp_str_len;
-  LPVOID read_str;
-  DWORD read_str_len;
-
-  guint32 dead_key_keyval;
-};
-
-
-/* GObject class methods */
-static void gtk_im_context_ime_class_init (GtkIMContextIMEClass *class);
-static void gtk_im_context_ime_init       (GtkIMContextIME      *context_ime);
-static void gtk_im_context_ime_dispose    (GObject              *obj);
-static void gtk_im_context_ime_finalize   (GObject              *obj);
-
-static void gtk_im_context_ime_set_property (GObject      *object,
-                                             guint         prop_id,
-                                             const GValue *value,
-                                             GParamSpec   *pspec);
-static void gtk_im_context_ime_get_property (GObject      *object,
-                                             guint         prop_id,
-                                             GValue       *value,
-                                             GParamSpec   *pspec);
-
-/* GtkIMContext's virtual functions */
-static void gtk_im_context_ime_set_client_widget   (GtkIMContext *context,
-                                                    GtkWidget    *widget);
-static gboolean gtk_im_context_ime_filter_keypress (GtkIMContext   *context,
-                                                    GdkEventKey    *event);
-static void gtk_im_context_ime_reset               (GtkIMContext   *context);
-static void gtk_im_context_ime_get_preedit_string  (GtkIMContext   *context,
-                                                    gchar         **str,
-                                                    PangoAttrList **attrs,
-                                                    gint           *cursor_pos);
-static void gtk_im_context_ime_focus_in            (GtkIMContext   *context);
-static void gtk_im_context_ime_focus_out           (GtkIMContext   *context);
-static void gtk_im_context_ime_set_cursor_location (GtkIMContext   *context,
-                                                    GdkRectangle   *area);
-static void gtk_im_context_ime_set_use_preedit     (GtkIMContext   *context,
-                                                    gboolean        use_preedit);
-
-/* GtkIMContextIME's private functions */
-static void gtk_im_context_ime_set_preedit_font (GtkIMContext    *context);
-
-static GdkFilterReturn
-gtk_im_context_ime_message_filter               (GdkXEvent       *xevent,
-                                                 GdkEvent        *event,
-                                                 gpointer         data);
-static void get_window_position                 (GdkWindow       *win,
-                                                 gint            *x,
-                                                 gint            *y);
-static void cb_client_widget_hierarchy_changed  (GtkWidget       *widget,
-                                                 GtkWidget       *widget2,
-                                                 GtkIMContextIME *context_ime);
-
-#define GTK_TYPE_IM_CONTEXT_IME (gtk_im_context_ime_get_type ())
-#define GTK_IM_CONTEXT_IME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIME))
-
-G_DEFINE_DYNAMIC_TYPE (GtkIMContextIME, gtk_im_context_ime, GTK_TYPE_IM_CONTEXT)
-
-void
-g_io_module_load (GIOModule *module)
-{
-  g_type_module_use (G_TYPE_MODULE (module));
-
-  gtk_im_context_ime_register_type (G_TYPE_MODULE (module));
-
-  g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
-                                  GTK_TYPE_IM_CONTEXT_IME,
-                                  "ime",
-                                  10);
-}
-
-void
-g_io_module_unload (GIOModule *module)
-{
-}
-
-char **
-g_io_module_query (void)
-{
-  char *eps[] = {
-    GTK_IM_MODULE_EXTENSION_POINT_NAME,
-    NULL
-  };
-
-  return g_strdupv (eps);
-}
-
-static void
-gtk_im_context_ime_class_init (GtkIMContextIMEClass *class)
-{
-  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
-  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-
-  gobject_class->finalize     = gtk_im_context_ime_finalize;
-  gobject_class->dispose      = gtk_im_context_ime_dispose;
-  gobject_class->set_property = gtk_im_context_ime_set_property;
-  gobject_class->get_property = gtk_im_context_ime_get_property;
-
-  im_context_class->set_client_widget   = gtk_im_context_ime_set_client_widget;
-  im_context_class->filter_keypress     = gtk_im_context_ime_filter_keypress;
-  im_context_class->reset               = gtk_im_context_ime_reset;
-  im_context_class->get_preedit_string  = gtk_im_context_ime_get_preedit_string;
-  im_context_class->focus_in            = gtk_im_context_ime_focus_in;
-  im_context_class->focus_out           = gtk_im_context_ime_focus_out;
-  im_context_class->set_cursor_location = gtk_im_context_ime_set_cursor_location;
-  im_context_class->set_use_preedit     = gtk_im_context_ime_set_use_preedit;
-}
-
-static void
-gtk_im_context_ime_class_finalize (GtkIMContextIMEClass *class)
-{
-}
-
-static void
-gtk_im_context_ime_init (GtkIMContextIME *context_ime)
-{
-  context_ime->client_window          = NULL;
-  context_ime->toplevel               = NULL;
-  context_ime->use_preedit            = TRUE;
-  context_ime->preediting             = FALSE;
-  context_ime->opened                 = FALSE;
-  context_ime->focus                  = FALSE;
-  context_ime->cursor_location.x      = 0;
-  context_ime->cursor_location.y      = 0;
-  context_ime->cursor_location.width  = 0;
-  context_ime->cursor_location.height = 0;
-  context_ime->commit_string          = NULL;
-
-  context_ime->priv = g_malloc0 (sizeof (GtkIMContextIMEPrivate));
-  context_ime->priv->conversion_mode  = 0;
-  context_ime->priv->sentence_mode    = 0;
-  context_ime->priv->comp_str         = NULL;
-  context_ime->priv->comp_str_len     = 0;
-  context_ime->priv->read_str         = NULL;
-  context_ime->priv->read_str_len     = 0;
-}
-
-
-static void
-gtk_im_context_ime_dispose (GObject *obj)
-{
-  GtkIMContext *context = GTK_IM_CONTEXT (obj);
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
-
-  if (context_ime->client_window)
-    gtk_im_context_ime_set_client_widget (context, NULL);
-
-  FREE_PREEDIT_BUFFER (context_ime);
-
-  if (G_OBJECT_CLASS (parent_class)->dispose)
-    G_OBJECT_CLASS (parent_class)->dispose (obj);
-}
-
-
-static void
-gtk_im_context_ime_finalize (GObject *obj)
-{
-  /* GtkIMContext *context = GTK_IM_CONTEXT (obj); */
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (obj);
-
-  g_free (context_ime->priv);
-  context_ime->priv = NULL;
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-
-static void
-gtk_im_context_ime_set_property (GObject      *object,
-                                 guint         prop_id,
-                                 const GValue *value,
-                                 GParamSpec   *pspec)
-{
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
-
-  switch (prop_id)
-    {
-    default:
-      break;
-    }
-}
-
-
-static void
-gtk_im_context_ime_get_property (GObject    *object,
-                                 guint       prop_id,
-                                 GValue     *value,
-                                 GParamSpec *pspec)
-{
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (object);
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
-
-  switch (prop_id)
-    {
-    default:
-      break;
-    }
-}
-
-
-GtkIMContext *
-gtk_im_context_ime_new (void)
-{
-  return g_object_new (GTK_TYPE_IM_CONTEXT_IME, NULL);
-}
-
-
-static void
-gtk_im_context_ime_set_client_widget (GtkIMContext *context,
-                                      GtkWidget    *widget)
-{
-  GtkIMContextIME *context_ime;
-  GtkWidget *toplevel;
-  GdkWindow *client_window;
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
-  context_ime = GTK_IM_CONTEXT_IME (context);
-  toplevel = gtk_widget_get_toplevel (widget);
-  client_window = gtk_widget_get_window (toplevel);
-
-  if (client_window)
-    {
-      HIMC himc;
-      HWND hwnd;
-
-      hwnd = gdk_win32_window_get_impl_hwnd (client_window);
-      himc = ImmGetContext (hwnd);
-      if (himc)
-       {
-         context_ime->opened = ImmGetOpenStatus (himc);
-         ImmGetConversionStatus (himc,
-                                 &context_ime->priv->conversion_mode,
-                                 &context_ime->priv->sentence_mode);
-         ImmReleaseContext (hwnd, himc);
-       }
-    }
-  else if (context_ime->focus)
-    {
-      gtk_im_context_ime_focus_out (context);
-    }
-
-  context_ime->client_window = client_window;
-}
-
-static gunichar
-_gtk_im_context_ime_dead_key_unichar (guint    keyval,
-                                      gboolean spacing)
-{
-  switch (keyval)
-    {
-#define CASE(keysym, unicode, spacing_unicode) \
-      case GDK_KEY_dead_##keysym: return (spacing) ? spacing_unicode : unicode;
-
-      CASE (grave, 0x0300, 0x0060);
-      CASE (acute, 0x0301, 0x00b4);
-      CASE (circumflex, 0x0302, 0x005e);
-      CASE (tilde, 0x0303, 0x007e);    /* Also used with perispomeni, 0x342. */
-      CASE (macron, 0x0304, 0x00af);
-      CASE (breve, 0x0306, 0x02d8);
-      CASE (abovedot, 0x0307, 0x02d9);
-      CASE (diaeresis, 0x0308, 0x00a8);
-      CASE (hook, 0x0309, 0);
-      CASE (abovering, 0x030A, 0x02da);
-      CASE (doubleacute, 0x030B, 0x2dd);
-      CASE (caron, 0x030C, 0x02c7);
-      CASE (abovecomma, 0x0313, 0);         /* Equivalent to psili */
-      CASE (abovereversedcomma, 0x0314, 0); /* Equivalent to dasia */
-      CASE (horn, 0x031B, 0);  /* Legacy use for psili, 0x313 (or 0x343). */
-      CASE (belowdot, 0x0323, 0);
-      CASE (cedilla, 0x0327, 0x00b8);
-      CASE (ogonek, 0x0328, 0);        /* Legacy use for dasia, 0x314.*/
-      CASE (iota, 0x0345, 0);
-
-#undef CASE
-    default:
-      return 0;
-    }
-}
-
-static void
-_gtk_im_context_ime_commit_unichar (GtkIMContextIME *context_ime,
-                                    gunichar         c)
-{
-  gchar utf8[10];
-  int len;
-
-  if (context_ime->priv->dead_key_keyval != 0)
-    {
-      gunichar combining;
-
-      combining =
-        _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval,
-                                              FALSE);
-      g_unichar_compose (c, combining, &c);
-    }
-
-  len = g_unichar_to_utf8 (c, utf8);
-  utf8[len] = 0;
-
-  g_signal_emit_by_name (context_ime, "commit", utf8);
-  context_ime->priv->dead_key_keyval = 0;
-}
-
-static gboolean
-gtk_im_context_ime_filter_keypress (GtkIMContext *context,
-                                    GdkEventKey  *event)
-{
-  GtkIMContextIME *context_ime;
-  gboolean retval = FALSE;
-  guint32 c;
-  GdkModifierType state;
-  guint keyval;
-
-  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
-  g_return_val_if_fail (event, FALSE);
-
-  if (gdk_event_get_event_type ((GdkEvent *) event) == GDK_KEY_RELEASE)
-    return FALSE;
-
-  gdk_event_get_state ((GdkEvent *) event, &state);
-
-  if (state & GDK_CONTROL_MASK)
-    return FALSE;
-
-  context_ime = GTK_IM_CONTEXT_IME (context);
-
-  if (!context_ime->focus)
-    return FALSE;
-
-  if (!GDK_IS_WINDOW (context_ime->client_window))
-    return FALSE;
-
-  gdk_event_get_keyval ((GdkEvent *) event, &keyval);
-
-  if (keyval == GDK_KEY_space &&
-      context_ime->priv->dead_key_keyval != 0)
-    {
-      c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
-      context_ime->priv->dead_key_keyval = 0;
-      _gtk_im_context_ime_commit_unichar (context_ime, c);
-      return TRUE;
-    }
-
-  c = gdk_keyval_to_unicode (keyval);
-
-  if (c)
-    {
-      _gtk_im_context_ime_commit_unichar (context_ime, c);
-      retval = TRUE;
-    }
-  else if (IS_DEAD_KEY (keyval))
-    {
-      gunichar dead_key;
-
-      dead_key = _gtk_im_context_ime_dead_key_unichar (keyval, FALSE);
-
-      /* Emulate double input of dead keys */
-      if (dead_key && keyval == context_ime->priv->dead_key_keyval)
-        {
-          c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
-          context_ime->priv->dead_key_keyval = 0;
-          _gtk_im_context_ime_commit_unichar (context_ime, c);
-          _gtk_im_context_ime_commit_unichar (context_ime, c);
-        }
-      else
-        context_ime->priv->dead_key_keyval = keyval;
-    }
-
-  return retval;
-}
-
-
-static void
-gtk_im_context_ime_reset (GtkIMContext *context)
-{
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
-  HWND hwnd;
-  HIMC himc;
-
-  if (!context_ime->client_window)
-    return;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return;
-
-  if (context_ime->preediting)
-    {
-      if (ImmGetOpenStatus (himc))
-        ImmNotifyIME (himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
-
-      context_ime->preediting = FALSE;
-      g_signal_emit_by_name (context, "preedit-changed");
-    }
-
-  ImmReleaseContext (hwnd, himc);
-}
-
-
-static gchar *
-get_utf8_preedit_string (GtkIMContextIME *context_ime, gint *pos_ret)
-{
-  gchar *utf8str = NULL;
-  HWND hwnd;
-  HIMC himc;
-  gint pos = 0;
-
-  if (pos_ret)
-    *pos_ret = 0;
-
-  if (!context_ime->client_window)
-    return g_strdup ("");
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return g_strdup ("");
-
-  if (context_ime->preediting)
-    {
-      glong len;
-
-      len = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
-      if (len > 0)
-       {
-         GError *error = NULL;
-         gpointer buf = g_alloca (len);
-
-         ImmGetCompositionStringW (himc, GCS_COMPSTR, buf, len);
-         len /= 2;
-         utf8str = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
-         if (error)
-           {
-             g_warning ("%s", error->message);
-             g_error_free (error);
-           }
-         
-         if (pos_ret)
-           {
-             pos = ImmGetCompositionStringW (himc, GCS_CURSORPOS, NULL, 0);
-             if (pos < 0 || len < pos)
-               {
-                 g_warning ("ImmGetCompositionString: "
-                            "Invalid cursor position!");
-                 pos = 0;
-               }
-           }
-       }
-    }
-
-  if (!utf8str)
-    {
-      utf8str = g_strdup ("");
-      pos = 0;
-    }
-
-  if (pos_ret)
-    *pos_ret = pos;
-
-  ImmReleaseContext (hwnd, himc);
-
-  return utf8str;
-}
-
-
-static PangoAttrList *
-get_pango_attr_list (GtkIMContextIME *context_ime, const gchar *utf8str)
-{
-  PangoAttrList *attrs = pango_attr_list_new ();
-  HWND hwnd;
-  HIMC himc;
-
-  if (!context_ime->client_window)
-    return attrs;
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return attrs;
-
-  if (context_ime->preediting)
-    {
-      const gchar *schr = utf8str, *echr;
-      guint8 *buf;
-      guint16 f_red, f_green, f_blue, b_red, b_green, b_blue;
-      glong len, spos = 0, epos, sidx = 0, eidx;
-      PangoAttribute *attr;
-
-      /*
-       *  get attributes list of IME.
-       */
-      len = ImmGetCompositionStringW (himc, GCS_COMPATTR, NULL, 0);
-      buf = g_alloca (len);
-      ImmGetCompositionStringW (himc, GCS_COMPATTR, buf, len);
-
-      /*
-       *  schr and echr are pointer in utf8str.
-       */
-      for (echr = g_utf8_next_char (utf8str); *schr != '\0';
-           echr = g_utf8_next_char (echr))
-        {
-          /*
-           *  spos and epos are buf(attributes list of IME) position by
-           *  bytes.
-           *  Using the wide-char API, this value is same with UTF-8 offset.
-           */
-         epos = g_utf8_pointer_to_offset (utf8str, echr);
-
-          /*
-           *  sidx and eidx are positions in utf8str by bytes.
-           */
-          eidx = echr - utf8str;
-
-          /*
-           *  convert attributes list to PangoAttriute.
-           */
-          if (*echr == '\0' || buf[spos] != buf[epos])
-            {
-              switch (buf[spos])
-                {
-                case ATTR_TARGET_CONVERTED:
-                  attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
-                  attr->start_index = sidx;
-                  attr->end_index = eidx;
-                  pango_attr_list_change (attrs, attr);
-                  f_red = f_green = f_blue = 0;
-                  b_red = b_green = b_blue = 0xffff;
-                  break;
-                case ATTR_TARGET_NOTCONVERTED:
-                  f_red = f_green = f_blue = 0xffff;
-                  b_red = b_green = b_blue = 0;
-                  break;
-                case ATTR_INPUT_ERROR:
-                  f_red = f_green = f_blue = 0;
-                  b_red = b_green = b_blue = 0x7fff;
-                  break;
-                default:        /* ATTR_INPUT,ATTR_CONVERTED,ATTR_FIXEDCONVERTED */
-                  attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
-                  attr->start_index = sidx;
-                  attr->end_index = eidx;
-                  pango_attr_list_change (attrs, attr);
-                  f_red = f_green = f_blue = 0;
-                  b_red = b_green = b_blue = 0xffff;
-                }
-              attr = pango_attr_foreground_new (f_red, f_green, f_blue);
-              attr->start_index = sidx;
-              attr->end_index = eidx;
-              pango_attr_list_change (attrs, attr);
-              attr = pango_attr_background_new (b_red, b_green, b_blue);
-              attr->start_index = sidx;
-              attr->end_index = eidx;
-              pango_attr_list_change (attrs, attr);
-
-              schr = echr;
-              spos = epos;
-              sidx = eidx;
-            }
-        }
-    }
-
-  ImmReleaseContext (hwnd, himc);
-
-  return attrs;
-}
-
-
-static void
-gtk_im_context_ime_get_preedit_string (GtkIMContext   *context,
-                                       gchar         **str,
-                                       PangoAttrList **attrs,
-                                       gint           *cursor_pos)
-{
-  gchar *utf8str = NULL;
-  gint pos = 0;
-  GtkIMContextIME *context_ime;
-
-  context_ime = GTK_IM_CONTEXT_IME (context);
-
-  utf8str = get_utf8_preedit_string (context_ime, &pos);
-
-  if (attrs)
-    *attrs = get_pango_attr_list (context_ime, utf8str);
-
-  if (str)
-    {
-      *str = utf8str;
-    }
-  else
-    {
-      g_free (utf8str);
-      utf8str = NULL;
-    }
-
-  if (cursor_pos)
-    *cursor_pos = pos;
-}
-
-
-static void
-gtk_im_context_ime_focus_in (GtkIMContext *context)
-{
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
-  GdkWindow *toplevel;
-  GtkWidget *widget = NULL;
-  HWND hwnd;
-  HIMC himc;
-
-  if (!GDK_IS_WINDOW (context_ime->client_window))
-    return;
-
-  /* swtich current context */
-  context_ime->focus = TRUE;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return;
-
-  toplevel = gdk_window_get_toplevel (context_ime->client_window);
-  if (GDK_IS_WINDOW (toplevel))
-    {
-      gdk_window_add_filter (toplevel,
-                             gtk_im_context_ime_message_filter, context_ime);
-      context_ime->toplevel = toplevel;
-    }
-  else
-    {
-      g_warning ("gtk_im_context_ime_focus_in(): "
-                 "cannot find toplevel window.");
-      return;
-    }
-
-  /* trace reparenting (probably no need) */
-  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
-  if (GTK_IS_WIDGET (widget))
-    {
-      g_signal_connect (widget, "hierarchy-changed",
-                        G_CALLBACK (cb_client_widget_hierarchy_changed),
-                        context_ime);
-    }
-  else
-    {
-      /* warning? */
-    }
-
-  /* restore preedit context */
-  ImmSetConversionStatus (himc,
-                          context_ime->priv->conversion_mode,
-                          context_ime->priv->sentence_mode);
-
-  if (context_ime->opened)
-    {
-      if (!ImmGetOpenStatus (himc))
-        ImmSetOpenStatus (himc, TRUE);
-      if (context_ime->preediting)
-        {
-          ImmSetCompositionStringW (himc,
-                                   SCS_SETSTR,
-                                   context_ime->priv->comp_str,
-                                   context_ime->priv->comp_str_len, NULL, 0);
-          FREE_PREEDIT_BUFFER (context_ime);
-        }
-    }
-
-  /* clean */
-  ImmReleaseContext (hwnd, himc);
-}
-
-
-static void
-gtk_im_context_ime_focus_out (GtkIMContext *context)
-{
-  GtkIMContextIME *context_ime = GTK_IM_CONTEXT_IME (context);
-  GdkWindow *toplevel;
-  GtkWidget *widget = NULL;
-  HWND hwnd;
-  HIMC himc;
-
-  if (!GDK_IS_WINDOW (context_ime->client_window))
-    return;
-
-  /* swtich current context */
-  context_ime->focus = FALSE;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return;
-
-  /* save preedit context */
-  ImmGetConversionStatus (himc,
-                          &context_ime->priv->conversion_mode,
-                          &context_ime->priv->sentence_mode);
-
-  if (ImmGetOpenStatus (himc))
-    {
-      gboolean preediting = context_ime->preediting;
-
-      if (preediting)
-        {
-          FREE_PREEDIT_BUFFER (context_ime);
-
-          context_ime->priv->comp_str_len
-            = ImmGetCompositionStringW (himc, GCS_COMPSTR, NULL, 0);
-          context_ime->priv->comp_str
-            = g_malloc (context_ime->priv->comp_str_len);
-          ImmGetCompositionStringW (himc, GCS_COMPSTR,
-                                   context_ime->priv->comp_str,
-                                   context_ime->priv->comp_str_len);
-
-          context_ime->priv->read_str_len
-            = ImmGetCompositionStringW (himc, GCS_COMPREADSTR, NULL, 0);
-          context_ime->priv->read_str
-            = g_malloc (context_ime->priv->read_str_len);
-          ImmGetCompositionStringW (himc, GCS_COMPREADSTR,
-                                   context_ime->priv->read_str,
-                                   context_ime->priv->read_str_len);
-        }
-
-      ImmSetOpenStatus (himc, FALSE);
-
-      context_ime->opened = TRUE;
-      context_ime->preediting = preediting;
-    }
-  else
-    {
-      context_ime->opened = FALSE;
-      context_ime->preediting = FALSE;
-    }
-
-  /* remove signal handler */
-  gdk_window_get_user_data (context_ime->client_window, (gpointer) & widget);
-  if (GTK_IS_WIDGET (widget))
-    {
-      g_signal_handlers_disconnect_by_func
-        (G_OBJECT (widget),
-         G_CALLBACK (cb_client_widget_hierarchy_changed), context_ime);
-    }
-
-  /* remove event fileter */
-  toplevel = gdk_window_get_toplevel (context_ime->client_window);
-  if (GDK_IS_WINDOW (toplevel))
-    {
-      gdk_window_remove_filter (toplevel,
-                                gtk_im_context_ime_message_filter,
-                                context_ime);
-      context_ime->toplevel = NULL;
-    }
-  else
-    {
-      g_warning ("gtk_im_context_ime_focus_out(): "
-                 "cannot find toplevel window.");
-    }
-
-  /* clean */
-  ImmReleaseContext (hwnd, himc);
-}
-
-
-static void
-gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
-                                        GdkRectangle *area)
-{
-  gint wx = 0, wy = 0;
-  GtkIMContextIME *context_ime;
-  COMPOSITIONFORM cf;
-  HWND hwnd;
-  HIMC himc;
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
-
-  context_ime = GTK_IM_CONTEXT_IME (context);
-  if (area)
-    context_ime->cursor_location = *area;
-
-  if (!context_ime->client_window)
-    return;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return;
-
-  get_window_position (context_ime->client_window, &wx, &wy);
-  cf.dwStyle = CFS_POINT;
-  cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
-  cf.ptCurrentPos.y = wy + context_ime->cursor_location.y;
-  ImmSetCompositionWindow (himc, &cf);
-
-  ImmReleaseContext (hwnd, himc);
-}
-
-
-static void
-gtk_im_context_ime_set_use_preedit (GtkIMContext *context,
-                                    gboolean      use_preedit)
-{
-  GtkIMContextIME *context_ime;
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
-  context_ime = GTK_IM_CONTEXT_IME (context);
-
-  context_ime->use_preedit = use_preedit;
-  if (context_ime->preediting)
-    {
-      HWND hwnd;
-      HIMC himc;
-
-      hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-      himc = ImmGetContext (hwnd);
-      if (!himc)
-        return;
-
-      /* FIXME: What to do? */
-
-      ImmReleaseContext (hwnd, himc);
-    }
-}
-
-
-static void
-gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
-{
-  GtkIMContextIME *context_ime;
-  GtkWidget *widget = NULL;
-  HWND hwnd;
-  HIMC himc;
-  HKL ime = GetKeyboardLayout (0);
-  const gchar *lang;
-  gunichar wc;
-  PangoContext *pango_context;
-  PangoFont *font;
-  LOGFONT *logfont;
-  GtkStyleContext *style;
-  PangoFontDescription *font_desc;
-
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
-
-  context_ime = GTK_IM_CONTEXT_IME (context);
-  if (!context_ime->client_window)
-    return;
-
-  gdk_window_get_user_data (context_ime->client_window, (gpointer) &widget);
-  if (!GTK_IS_WIDGET (widget))
-    return;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return;
-
-  /* set font */
-  pango_context = gtk_widget_get_pango_context (widget);
-  if (!pango_context)
-    goto ERROR_OUT;
-
-  /* Try to make sure we use a font that actually can show the
-   * language in question.
-   */ 
-
-  switch (PRIMARYLANGID (LOWORD (ime)))
-    {
-    case LANG_JAPANESE:
-      lang = "ja"; break;
-    case LANG_KOREAN:
-      lang = "ko"; break;
-    case LANG_CHINESE:
-      switch (SUBLANGID (LOWORD (ime)))
-       {
-       case SUBLANG_CHINESE_TRADITIONAL:
-         lang = "zh_TW"; break;
-       case SUBLANG_CHINESE_SIMPLIFIED:
-         lang = "zh_CN"; break;
-       case SUBLANG_CHINESE_HONGKONG:
-         lang = "zh_HK"; break;
-       case SUBLANG_CHINESE_SINGAPORE:
-         lang = "zh_SG"; break;
-       case SUBLANG_CHINESE_MACAU:
-         lang = "zh_MO"; break;
-       default:
-         lang = "zh"; break;
-       }
-      break;
-    default:
-      lang = ""; break;
-    }
-
-  style = gtk_widget_get_style_context (widget);
-  gtk_style_context_save (style);
-  gtk_style_context_set_state (style, GTK_STATE_FLAG_NORMAL);
-  gtk_style_context_get (style,
-                         "font",
-                         &font_desc,
-                         NULL);
-  gtk_style_context_restore (style);
-  
-  if (lang[0])
-    {
-      /* We know what language it is. Look for a character, any
-       * character, that language needs.
-       */
-      PangoLanguage *pango_lang = pango_language_from_string (lang);
-      PangoFontset *fontset =
-        pango_context_load_fontset (pango_context,
-                                                           font_desc,
-                                                           pango_lang);
-      gunichar *sample =
-       g_utf8_to_ucs4 (pango_language_get_sample_string (pango_lang),
-                       -1, NULL, NULL, NULL);
-      wc = 0x4E00;             /* In all CJK languages? */
-      if (sample != NULL)
-       {
-         int i;
-
-         for (i = 0; sample[i]; i++)
-           if (g_unichar_iswide (sample[i]))
-             {
-               wc = sample[i];
-               break;
-             }
-         g_free (sample);
-       }
-      font = pango_fontset_get_font (fontset, wc);
-      g_object_unref (fontset);
-    }
-  else
-    font = pango_context_load_font (pango_context, font_desc);
-
-  if (!font)
-    goto ERROR_OUT;
-
-  logfont = pango_win32_font_logfont (font);
-  if (logfont)
-    ImmSetCompositionFont (himc, logfont);
-
-  g_object_unref (font);
-
-ERROR_OUT:
-  /* clean */
-  ImmReleaseContext (hwnd, himc);
-}
-
-
-static GdkFilterReturn
-gtk_im_context_ime_message_filter (GdkXEvent *xevent,
-                                   GdkEvent  *event,
-                                   gpointer   data)
-{
-  GtkIMContext *context;
-  GtkIMContextIME *context_ime;
-  HWND hwnd;
-  HIMC himc;
-  MSG *msg = (MSG *) xevent;
-  GdkFilterReturn retval = GDK_FILTER_CONTINUE;
-
-  g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (data), retval);
-
-  context = GTK_IM_CONTEXT (data);
-  context_ime = GTK_IM_CONTEXT_IME (data);
-  if (!context_ime->focus)
-    return retval;
-
-  hwnd = gdk_win32_window_get_impl_hwnd (context_ime->client_window);
-  himc = ImmGetContext (hwnd);
-  if (!himc)
-    return retval;
-
-  switch (msg->message)
-    {
-    case WM_IME_COMPOSITION:
-      {
-        gint wx = 0, wy = 0;
-        CANDIDATEFORM cf;
-
-        get_window_position (context_ime->client_window, &wx, &wy);
-        /* FIXME! */
-        {
-          HWND hwnd_top;
-          POINT pt;
-          RECT rc;
-
-          hwnd_top =
-            gdk_win32_window_get_impl_hwnd (gdk_window_get_toplevel
-                                            (context_ime->client_window));
-          GetWindowRect (hwnd_top, &rc);
-          pt.x = wx;
-          pt.y = wy;
-          ClientToScreen (hwnd_top, &pt);
-          wx = pt.x - rc.left;
-          wy = pt.y - rc.top;
-        }
-        cf.dwIndex = 0;
-        cf.dwStyle = CFS_CANDIDATEPOS;
-        cf.ptCurrentPos.x = wx + context_ime->cursor_location.x;
-        cf.ptCurrentPos.y = wy + context_ime->cursor_location.y
-          + context_ime->cursor_location.height;
-        ImmSetCandidateWindow (himc, &cf);
-
-        if ((msg->lParam & GCS_COMPSTR))
-          g_signal_emit_by_name (context, "preedit-changed");
-
-        if (msg->lParam & GCS_RESULTSTR)
-          {
-            gsize len;
-            gchar *utf8str = NULL;
-            GError *error = NULL;
-
-            len = ImmGetCompositionStringW (himc, GCS_RESULTSTR, NULL, 0);
-
-            if (len > 0)
-              {
-                gpointer buf = g_alloca (len);
-                ImmGetCompositionStringW (himc, GCS_RESULTSTR, buf, len);
-                len /= 2;
-                context_ime->commit_string = g_utf16_to_utf8 (buf, len, NULL, NULL, &error);
-                if (error)
-                  {
-                    g_warning ("%s", error->message);
-                    g_error_free (error);
-                  }
-              }
-
-            if (context_ime->commit_string)
-              retval = TRUE;
-          }
-
-        if (context_ime->use_preedit)
-          retval = TRUE;
-        break;
-      }
-
-    case WM_IME_STARTCOMPOSITION:
-      context_ime->preediting = TRUE;
-      gtk_im_context_ime_set_cursor_location (context, NULL);
-      g_signal_emit_by_name (context, "preedit-start");
-      if (context_ime->use_preedit)
-        retval = TRUE;
-      break;
-
-    case WM_IME_ENDCOMPOSITION:
-      context_ime->preediting = FALSE;
-      g_signal_emit_by_name (context, "preedit-changed");
-      g_signal_emit_by_name (context, "preedit-end");
-
-      if (context_ime->commit_string)
-        {
-          g_signal_emit_by_name (context, "commit", context_ime->commit_string);
-          g_free (context_ime->commit_string);
-          context_ime->commit_string = NULL;
-        }
-
-      if (context_ime->use_preedit)
-        retval = TRUE;
-      break;
-
-    case WM_IME_NOTIFY:
-      switch (msg->wParam)
-        {
-        case IMN_SETOPENSTATUS:
-          context_ime->opened = ImmGetOpenStatus (himc);
-          gtk_im_context_ime_set_preedit_font (context);
-          break;
-
-        default:
-          break;
-        }
-
-    default:
-      break;
-    }
-
-  ImmReleaseContext (hwnd, himc);
-  return retval;
-}
-
-
-/*
- * x and y must be initialized to 0.
- */
-static void
-get_window_position (GdkWindow *win, gint *x, gint *y)
-{
-  GdkWindow *parent, *toplevel;
-  gint wx, wy;
-
-  g_return_if_fail (GDK_IS_WINDOW (win));
-  g_return_if_fail (x && y);
-
-  gdk_window_get_position (win, &wx, &wy);
-  *x += wx;
-  *y += wy;
-  parent = gdk_window_get_parent (win);
-  toplevel = gdk_window_get_toplevel (win);
-
-  if (parent && parent != toplevel)
-    get_window_position (parent, x, y);
-}
-
-
-/*
- *  probably, this handler isn't needed.
- */
-static void
-cb_client_widget_hierarchy_changed (GtkWidget       *widget,
-                                    GtkWidget       *widget2,
-                                    GtkIMContextIME *context_ime)
-{
-  GdkWindow *new_toplevel;
-
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context_ime));
-
-  if (!context_ime->client_window)
-    return;
-  if (!context_ime->focus)
-    return;
-
-  new_toplevel = gdk_window_get_toplevel (context_ime->client_window);
-  if (context_ime->toplevel == new_toplevel)
-    return;
-
-  /* remove filter from old toplevel */
-  if (GDK_IS_WINDOW (context_ime->toplevel))
-    {
-      gdk_window_remove_filter (context_ime->toplevel,
-                                gtk_im_context_ime_message_filter,
-                                context_ime);
-    }
-  else
-    {
-    }
-
-  /* add filter to new toplevel */
-  if (GDK_IS_WINDOW (new_toplevel))
-    {
-      gdk_window_add_filter (new_toplevel,
-                             gtk_im_context_ime_message_filter, context_ime);
-    }
-  else
-    {
-    }
-
-  context_ime->toplevel = new_toplevel;
-}
diff --git a/modules/input/gtkimcontextime.h b/modules/input/gtkimcontextime.h
deleted file mode 100644 (file)
index 6bb0365..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * gtkimmoduleime
- * Copyright (C) 2003 Takuro Ashie
- * Copyright (C) 2003 Kazuki IWAMOTO
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * $Id$
- */
-
-#include <gtk/gtk.h>
-
-#define GTK_TYPE_IM_CONTEXT_IME            gtk_type_im_context_ime
-#define GTK_IM_CONTEXT_IME(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIME))
-#define GTK_IM_CONTEXT_IME_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIMEClass))
-#define GTK_IS_IM_CONTEXT_IME(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_IM_CONTEXT_IME))
-#define GTK_IS_IM_CONTEXT_IME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IM_CONTEXT_IME))
-#define GTK_IM_CONTEXT_IME_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_IM_CONTEXT_IME, GtkIMContextIMEClass))
-
-typedef struct _GtkIMContextIME GtkIMContextIME;
-typedef struct _GtkIMContextIMEPrivate GtkIMContextIMEPrivate;
-typedef struct _GtkIMContextIMEClass GtkIMContextIMEClass;
-
-struct _GtkIMContextIME
-{
-  GtkIMContext object;
-
-  GdkWindow *client_window;
-  GdkWindow *toplevel;
-  guint use_preedit : 1;
-  guint preediting : 1;
-  guint opened : 1;
-  guint focus : 1;
-  GdkRectangle cursor_location;
-  gchar *commit_string;
-
-  GtkIMContextIMEPrivate *priv;
-};
-
-struct _GtkIMContextIMEClass
-{
-  GtkIMContextClass parent_class;
-};
-
-
-void          gtk_im_context_ime_register_type (GTypeModule * type_module);
-GtkIMContext *gtk_im_context_ime_new           (void);
diff --git a/modules/input/gtkimcontextxim.c b/modules/input/gtkimcontextxim.c
deleted file mode 100644 (file)
index 03ce3e7..0000000
+++ /dev/null
@@ -1,1804 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) 2000 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include "locale.h"
-#include <string.h>
-#include <stdlib.h>
-
-#include "gtkimmodule.h"
-#include "gtkimcontextxim.h"
-
-#include "gtk/gtkintl.h"
-
-typedef struct _StatusWindow StatusWindow;
-typedef struct _GtkXIMInfo GtkXIMInfo;
-
-struct _GtkIMContextXIM
-{
-  GtkIMContext object;
-
-  GtkXIMInfo *im_info;
-
-  gchar *locale;
-  gchar *mb_charset;
-
-  GdkWindow *client_window;
-  Window client_window_xid;
-  GtkWidget *client_widget;
-
-  /* The status window for this input context; we claim the
-   * status window when we are focused and have created an XIC
-   */
-  StatusWindow *status_window;
-
-  gint preedit_size;
-  gint preedit_length;
-  gunichar *preedit_chars;
-  XIMFeedback *feedbacks;
-
-  gint preedit_cursor;
-  
-  XIMCallback preedit_start_callback;
-  XIMCallback preedit_done_callback;
-  XIMCallback preedit_draw_callback;
-  XIMCallback preedit_caret_callback;
-
-  XIMCallback status_start_callback;
-  XIMCallback status_done_callback;
-  XIMCallback status_draw_callback;
-
-  XIMCallback string_conversion_callback;
-
-  XIC ic;
-
-  guint filter_key_release : 1;
-  guint use_preedit : 1;
-  guint finalizing : 1;
-  guint in_toplevel : 1;
-  guint has_focus : 1;
-};
-
-struct _GtkXIMInfo
-{
-  GdkDisplay *display;
-  XIM im;
-  char *locale;
-  XIMStyle preedit_style_setting;
-  XIMStyle status_style_setting;
-  XIMStyle style;
-  GtkSettings *settings;
-  gulong status_set;
-  gulong preedit_set;
-  gulong display_closed_cb;
-  XIMStyles *xim_styles;
-  GSList *ics;
-
-  guint reconnecting :1;
-  guint supports_string_conversion;
-};
-
-/* A context status window; these are kept in the status_windows list. */
-struct _StatusWindow
-{
-  GtkWidget *window;
-  
-  /* Toplevel window to which the status window corresponds */
-  GtkWidget *toplevel;
-
-  /* Currently focused GtkIMContextXIM for the toplevel, if any */
-  GtkIMContextXIM *context;
-};
-
-static void     gtk_im_context_xim_class_init         (GtkIMContextXIMClass  *class);
-static void     gtk_im_context_xim_init               (GtkIMContextXIM       *im_context_xim);
-static void     gtk_im_context_xim_finalize           (GObject               *obj);
-static void     gtk_im_context_xim_set_client_widget  (GtkIMContext          *context,
-                                                       GtkWidget             *widget);
-static gboolean gtk_im_context_xim_filter_keypress    (GtkIMContext          *context,
-                                                      GdkEventKey           *key);
-static void     gtk_im_context_xim_reset              (GtkIMContext          *context);
-static void     gtk_im_context_xim_focus_in           (GtkIMContext          *context);
-static void     gtk_im_context_xim_focus_out          (GtkIMContext          *context);
-static void     gtk_im_context_xim_set_cursor_location (GtkIMContext          *context,
-                                                      GdkRectangle             *area);
-static void     gtk_im_context_xim_set_use_preedit    (GtkIMContext          *context,
-                                                      gboolean               use_preedit);
-static void     gtk_im_context_xim_get_preedit_string (GtkIMContext          *context,
-                                                      gchar                **str,
-                                                      PangoAttrList        **attrs,
-                                                      gint                  *cursor_pos);
-
-static void reinitialize_ic      (GtkIMContextXIM *context_xim);
-static void set_ic_client_window (GtkIMContextXIM *context_xim,
-                                 GdkWindow       *client_window);
-
-static void setup_styles (GtkXIMInfo *info);
-
-static void update_client_widget   (GtkIMContextXIM *context_xim);
-static void update_status_window   (GtkIMContextXIM *context_xim);
-
-static StatusWindow *status_window_get      (GtkWidget    *toplevel);
-static void          status_window_free     (StatusWindow *status_window);
-static void          status_window_set_text (StatusWindow *status_window,
-                                            const gchar  *text);
-
-static void xim_destroy_callback   (XIM      xim,
-                                   XPointer client_data,
-                                   XPointer call_data);
-
-static XIC       gtk_im_context_xim_get_ic            (GtkIMContextXIM *context_xim);
-static void           xim_info_display_closed (GdkDisplay *display,
-                                              gboolean    is_error,
-                                              GtkXIMInfo *info);
-
-G_DEFINE_DYNAMIC_TYPE (GtkIMContextXIM, gtk_im_context_xim, GTK_TYPE_IM_CONTEXT)
-
-void
-g_io_module_load (GIOModule *module)
-{
-  g_type_module_use (G_TYPE_MODULE (module));
-
-  g_print ("load io module for x11\n");
-  gtk_im_context_xim_register_type (G_TYPE_MODULE (module));
-
-  g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
-                                  GTK_TYPE_IM_CONTEXT_XIM,
-                                  "xim",
-                                  10);
-}
-
-void
-g_io_module_unload (GIOModule *module)
-{
-}
-
-char **
-g_io_module_query (void)
-{
-  char *eps[] = {
-    GTK_IM_MODULE_EXTENSION_POINT_NAME,
-    NULL
-  };
-
-  return g_strdupv (eps);
-}
-
-static GSList *open_ims = NULL;
-
-/* List of status windows for different toplevels */
-static GSList *status_windows = NULL;
-
-#define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \
-                     XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone)
-#define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \
-                     XIMStatusNothing | XIMStatusNone)
-#define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \
-                     XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone)
-
-static XIMStyle 
-choose_better_style (XIMStyle style1, XIMStyle style2) 
-{
-  XIMStyle s1, s2, u; 
-  
-  if (style1 == 0) return style2;
-  if (style2 == 0) return style1;
-  if ((style1 & (PREEDIT_MASK | STATUS_MASK))
-       == (style2 & (PREEDIT_MASK | STATUS_MASK)))
-    return style1;
-
-  s1 = style1 & PREEDIT_MASK;
-  s2 = style2 & PREEDIT_MASK;
-  u = s1 | s2;
-  if (s1 != s2) {
-    if (u & XIMPreeditCallbacks)
-      return (s1 == XIMPreeditCallbacks) ? style1 : style2;
-    else if (u & XIMPreeditPosition)
-      return (s1 == XIMPreeditPosition) ? style1 :style2;
-    else if (u & XIMPreeditArea)
-      return (s1 == XIMPreeditArea) ? style1 : style2;
-    else if (u & XIMPreeditNothing)
-      return (s1 == XIMPreeditNothing) ? style1 : style2;
-    else if (u & XIMPreeditNone)
-      return (s1 == XIMPreeditNone) ? style1 : style2;
-  } else {
-    s1 = style1 & STATUS_MASK;
-    s2 = style2 & STATUS_MASK;
-    u = s1 | s2;
-    if (u & XIMStatusCallbacks)
-      return (s1 == XIMStatusCallbacks) ? style1 : style2;
-    else if (u & XIMStatusArea)
-      return (s1 == XIMStatusArea) ? style1 : style2;
-    else if (u & XIMStatusNothing)
-      return (s1 == XIMStatusNothing) ? style1 : style2;
-    else if (u & XIMStatusNone)
-      return (s1 == XIMStatusNone) ? style1 : style2;
-  }
-  return 0; /* Get rid of stupid warning */
-}
-
-static void
-reinitialize_all_ics (GtkXIMInfo *info)
-{
-  GSList *tmp_list;
-
-  for (tmp_list = info->ics; tmp_list; tmp_list = tmp_list->next)
-    reinitialize_ic (tmp_list->data);
-}
-
-static void
-setup_styles (GtkXIMInfo *info)
-{
-  int i;
-  unsigned long settings_preference;
-  XIMStyles *xim_styles = info->xim_styles;
-
-  settings_preference = info->status_style_setting|info->preedit_style_setting;
-  info->style = 0;
-  if (xim_styles)
-    {
-      for (i = 0; i < xim_styles->count_styles; i++)
-       if ((xim_styles->supported_styles[i] & ALLOWED_MASK) == xim_styles->supported_styles[i])
-         {
-           if (settings_preference == xim_styles->supported_styles[i])
-             {
-               info->style = settings_preference;
-               break;
-             }
-           info->style = choose_better_style (info->style,
-                                              xim_styles->supported_styles[i]);
-         }
-    }
-  if (info->style == 0)
-    info->style = XIMPreeditNothing | XIMStatusNothing;
-}
-
-static void
-setup_im (GtkXIMInfo *info)
-{
-  XIMValuesList *ic_values = NULL;
-  XIMCallback im_destroy_callback;
-  GdkDisplay *display;
-
-  if (info->im == NULL)
-    return;
-
-  im_destroy_callback.client_data = (XPointer)info;
-  im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
-  XSetIMValues (info->im,
-               XNDestroyCallback, &im_destroy_callback,
-               NULL);
-
-  XGetIMValues (info->im,
-               XNQueryInputStyle, &info->xim_styles,
-               XNQueryICValuesList, &ic_values,
-               NULL);
-
-  info->supports_string_conversion = FALSE;
-  if (ic_values)
-    {
-      int i;
-      
-      for (i = 0; i < ic_values->count_values; i++)
-       if (strcmp (ic_values->supported_values[i],
-                   XNStringConversionCallback) == 0)
-         {
-           info->supports_string_conversion = TRUE;
-           break;
-         }
-
-#if 0
-      for (i = 0; i < ic_values->count_values; i++)
-       g_print ("%s\n", ic_values->supported_values[i]);
-      for (i = 0; i < xim_styles->count_styles; i++)
-       g_print ("%#x\n", xim_styles->supported_styles[i]);
-#endif
-      
-      XFree (ic_values);
-    }
-
-  info->status_style_setting = XIMStatusCallbacks;
-  info->preedit_style_setting = XIMPreeditCallbacks;
-  setup_styles (info);
-  reinitialize_all_ics (info);
-
-  display = info->display;
-  info->display_closed_cb = g_signal_connect (display, "closed",
-                                             G_CALLBACK (xim_info_display_closed), info);
-}
-
-static void
-xim_info_display_closed (GdkDisplay *display,
-                        gboolean    is_error,
-                        GtkXIMInfo *info)
-{
-  GSList *ics, *tmp_list;
-
-  open_ims = g_slist_remove (open_ims, info);
-
-  ics = info->ics;
-  info->ics = NULL;
-
-  for (tmp_list = ics; tmp_list; tmp_list = tmp_list->next)
-    set_ic_client_window (tmp_list->data, NULL);
-
-  g_slist_free (ics);
-
-  if (info->status_set)
-    g_signal_handler_disconnect (info->settings, info->status_set);
-  if (info->preedit_set)
-    g_signal_handler_disconnect (info->settings, info->preedit_set);
-  if (info->display_closed_cb)
-    g_signal_handler_disconnect (display, info->display_closed_cb);
-
-  if (info->xim_styles)
-    XFree (info->xim_styles);
-  g_free (info->locale);
-
-  if (info->im)
-    XCloseIM (info->im);
-
-  g_free (info);
-}
-
-static void
-xim_instantiate_callback (Display *display, XPointer client_data,
-                         XPointer call_data)
-{
-  GtkXIMInfo *info = (GtkXIMInfo*)client_data;
-  XIM im = NULL;
-
-  im = XOpenIM (display, NULL, NULL, NULL);
-
-  if (!im)
-    return;
-
-  info->im = im;
-  setup_im (info);
-
-  XUnregisterIMInstantiateCallback (display, NULL, NULL, NULL,
-                                   xim_instantiate_callback,
-                                   (XPointer)info);
-  info->reconnecting = FALSE;
-}
-
-/* initialize info->im */
-static void
-xim_info_try_im (GtkXIMInfo *info)
-{
-  GdkDisplay *display = info->display;
-
-  g_assert (info->im == NULL);
-  if (info->reconnecting)
-    return;
-
-  if (XSupportsLocale ())
-    {
-      if (!XSetLocaleModifiers (""))
-       g_warning ("Unable to set locale modifiers with XSetLocaleModifiers()");
-      info->im = XOpenIM (GDK_DISPLAY_XDISPLAY (display), NULL, NULL, NULL);
-      if (!info->im)
-       {
-         XRegisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY(display),
-                                         NULL, NULL, NULL,
-                                         xim_instantiate_callback,
-                                         (XPointer)info);
-         info->reconnecting = TRUE;
-         return;
-       }
-      setup_im (info);
-    }
-}
-
-static void
-xim_destroy_callback (XIM      xim,
-                     XPointer client_data,
-                     XPointer call_data)
-{
-  GtkXIMInfo *info = (GtkXIMInfo*)client_data;
-
-  info->im = NULL;
-
-  g_signal_handler_disconnect (info->settings, info->status_set);
-  info->status_set = 0;
-  g_signal_handler_disconnect (info->settings, info->preedit_set);
-  info->preedit_set = 0;
-
-  reinitialize_all_ics (info);
-  xim_info_try_im (info);
-  return;
-} 
-
-static GtkXIMInfo *
-get_im (GdkWindow *client_window,
-       const char *locale)
-{
-  GSList *tmp_list;
-  GtkXIMInfo *info;
-  GdkDisplay *display = gdk_window_get_display (client_window);
-
-  info = NULL;
-  tmp_list = open_ims;
-  while (tmp_list)
-    {
-      GtkXIMInfo *tmp_info = tmp_list->data;
-      if (tmp_info->display == display &&
-         strcmp (tmp_info->locale, locale) == 0)
-       {
-         if (tmp_info->im)
-           {
-             return tmp_info;
-           }
-         else
-           {
-             tmp_info = tmp_info;
-             break;
-           }
-       }
-      tmp_list = tmp_list->next;
-    }
-
-  if (info == NULL)
-    {
-      info = g_new (GtkXIMInfo, 1);
-      open_ims = g_slist_prepend (open_ims, info);
-
-      info->display = display;
-      info->locale = g_strdup (locale);
-      info->xim_styles = NULL;
-      info->preedit_style_setting = 0;
-      info->status_style_setting = 0;
-      info->settings = NULL;
-      info->preedit_set = 0;
-      info->status_set = 0;
-      info->display_closed_cb = 0;
-      info->ics = NULL;
-      info->reconnecting = FALSE;
-      info->im = NULL;
-    }
-
-  xim_info_try_im (info);
-  return info;
-}
-
-static void
-gtk_im_context_xim_class_init (GtkIMContextXIMClass *class)
-{
-  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
-  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-
-  im_context_class->set_client_widget = gtk_im_context_xim_set_client_widget;
-  im_context_class->filter_keypress = gtk_im_context_xim_filter_keypress;
-  im_context_class->reset = gtk_im_context_xim_reset;
-  im_context_class->get_preedit_string = gtk_im_context_xim_get_preedit_string;
-  im_context_class->focus_in = gtk_im_context_xim_focus_in;
-  im_context_class->focus_out = gtk_im_context_xim_focus_out;
-  im_context_class->set_cursor_location = gtk_im_context_xim_set_cursor_location;
-  im_context_class->set_use_preedit = gtk_im_context_xim_set_use_preedit;
-  gobject_class->finalize = gtk_im_context_xim_finalize;
-}
-
-static void
-gtk_im_context_xim_class_finalize (GtkIMContextXIMClass *class)
-{
-}
-
-static void
-gtk_im_context_xim_init (GtkIMContextXIM *im_context_xim)
-{
-  im_context_xim->use_preedit = TRUE;
-  im_context_xim->filter_key_release = FALSE;
-  im_context_xim->finalizing = FALSE;
-  im_context_xim->has_focus = FALSE;
-  im_context_xim->in_toplevel = FALSE;
-}
-
-static void
-gtk_im_context_xim_finalize (GObject *obj)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (obj);
-
-  context_xim->finalizing = TRUE;
-
-  if (context_xim->im_info && !context_xim->im_info->ics->next) 
-    {
-      if (context_xim->im_info->reconnecting)
-       {
-         GdkDisplay *display;
-
-         display = context_xim->im_info->display;
-         XUnregisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY (display),
-                                           NULL, NULL, NULL,
-                                           xim_instantiate_callback,
-                                           (XPointer)context_xim->im_info);
-       }
-      else if (context_xim->im_info->im)
-       {
-         XIMCallback im_destroy_callback;
-
-         im_destroy_callback.client_data = NULL;
-         im_destroy_callback.callback = NULL;
-         XSetIMValues (context_xim->im_info->im,
-                       XNDestroyCallback, &im_destroy_callback,
-                       NULL);
-       }
-    }
-
-  set_ic_client_window (context_xim, NULL);
-
-  g_free (context_xim->locale);
-  g_free (context_xim->mb_charset);
-
-  G_OBJECT_CLASS (gtk_im_context_xim_parent_class)->finalize (obj);
-}
-
-static void
-reinitialize_ic (GtkIMContextXIM *context_xim)
-{
-  if (context_xim->ic)
-    {
-      XDestroyIC (context_xim->ic);
-      context_xim->ic = NULL;
-      update_status_window (context_xim);
-
-      if (context_xim->preedit_length)
-       {
-         context_xim->preedit_length = 0;
-         if (!context_xim->finalizing)
-           g_signal_emit_by_name (context_xim, "preedit-changed");
-       }
-    }
-  /* 
-     reset filter_key_release flag, otherwise keystrokes will be doubled
-     until reconnecting to XIM.
-  */
-  context_xim->filter_key_release = FALSE;
-}
-
-static void
-set_ic_client_window (GtkIMContextXIM *context_xim,
-                     GdkWindow       *client_window)
-{
-  reinitialize_ic (context_xim);
-  if (context_xim->client_window)
-    {
-      context_xim->im_info->ics = g_slist_remove (context_xim->im_info->ics, context_xim);
-      context_xim->im_info = NULL;
-    }
-  
-  context_xim->client_window = client_window;
-  context_xim->client_window_xid = None;
-
-  if (context_xim->client_window)
-    {
-      GdkWindow *native;
-
-      context_xim->im_info = get_im (context_xim->client_window, context_xim->locale);
-      context_xim->im_info->ics = g_slist_prepend (context_xim->im_info->ics, context_xim);
-
-      for (native = client_window; native; native = gdk_window_get_parent (native))
-        {
-          if (gdk_window_has_native (native))
-            {
-              context_xim->client_window_xid = gdk_x11_window_get_xid (native);
-              break;
-            }
-        }
-    }
-  
-  update_client_widget (context_xim);
-}
-
-static void
-gtk_im_context_xim_set_client_widget (GtkIMContext *context,
-                                      GtkWidget    *widget)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
-
-  set_ic_client_window (context_xim, gtk_widget_get_window (toplevel));
-}
-
-GtkIMContext *
-gtk_im_context_xim_new (void)
-{
-  GtkIMContextXIM *result;
-  const gchar *charset;
-
-  if (!GDK_IS_X11_DISPLAY(gdk_display_get_default()))
-    return NULL;
-  result = g_object_new (GTK_TYPE_IM_CONTEXT_XIM, NULL);
-
-  result->locale = g_strdup (setlocale (LC_CTYPE, NULL));
-  
-  g_get_charset (&charset);
-  result->mb_charset = g_strdup (charset);
-
-  return GTK_IM_CONTEXT (result);
-}
-
-static char *
-mb_to_utf8 (GtkIMContextXIM *context_xim,
-           const char      *str)
-{
-  GError *error = NULL;
-  gchar *result;
-
-  if (strcmp (context_xim->mb_charset, "UTF-8") == 0)
-    result = g_strdup (str);
-  else
-    {
-      result = g_convert (str, -1,
-                         "UTF-8", context_xim->mb_charset,
-                         NULL, NULL, &error);
-      if (!result)
-       {
-         g_warning ("Error converting text from IM to UTF-8: %s\n", error->message);
-         g_error_free (error);
-       }
-    }
-  
-  return result;
-}
-
-static gboolean
-gtk_im_context_xim_filter_keypress (GtkIMContext *context,
-                                   GdkEventKey  *event)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  XIC ic = gtk_im_context_xim_get_ic (context_xim);
-  gchar static_buffer[256];
-  gchar *buffer = static_buffer;
-  gint buffer_size = sizeof(static_buffer) - 1;
-  gint num_bytes = 0;
-  KeySym keysym;
-  Status status;
-  gboolean result = FALSE;
-  GdkWindow *window;
-  XKeyPressedEvent xevent;
-  GdkEventType event_type;
-  guint state;
-
-  event_type = gdk_event_get_event_type ((GdkEvent *) event);
-
-  if (!gdk_event_get_state ((GdkEvent *) event, &state))
-    return GDK_EVENT_PROPAGATE;
-
-  if (event_type == GDK_KEY_RELEASE && !context_xim->filter_key_release)
-    return FALSE;
-
-  window = gdk_window_get_toplevel (gdk_event_get_window ((GdkEvent *) event));
-
-  xevent.type = (event_type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
-  xevent.serial = 0;           /* hope it doesn't matter */
-  xevent.send_event = gdk_event_is_sent ((GdkEvent *)event);
-  xevent.display = GDK_WINDOW_XDISPLAY (window);
-  xevent.window = GDK_WINDOW_XID (window);
-  xevent.root = DefaultRootWindow(GDK_WINDOW_XDISPLAY (window));
-  xevent.subwindow = xevent.window;
-  xevent.time = gdk_event_get_time ((GdkEvent *) event);
-  xevent.x = xevent.x_root = 0;
-  xevent.y = xevent.y_root = 0;
-  xevent.state = state;
-  xevent.keycode = gdk_event_get_scancode ((GdkEvent *) event);
-  xevent.same_screen = True;
-  
-  if (XFilterEvent ((XEvent *)&xevent, context_xim->client_window_xid))
-    return TRUE;
-  
-  if (state &
-      (gtk_accelerator_get_default_mod_mask () & ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK))) 
-    return FALSE;
-
- again:
-  if (ic)
-    num_bytes = XmbLookupString (ic, &xevent, buffer, buffer_size, &keysym, &status);
-  else
-    {
-      num_bytes = XLookupString (&xevent, buffer, buffer_size, &keysym, NULL);
-      status = XLookupBoth;
-    }
-
-  if (status == XBufferOverflow)
-    {
-      buffer_size = num_bytes;
-      if (buffer != static_buffer) 
-       g_free (buffer);
-      buffer = g_malloc (num_bytes + 1);
-      goto again;
-    }
-
-  /* I don't know how we should properly handle XLookupKeysym or XLookupBoth
-   * here ... do input methods actually change the keysym? we can't really
-   * feed it back to accelerator processing at this point...
-   */
-  if (status == XLookupChars || status == XLookupBoth)
-    {
-      char *result_utf8;
-
-      buffer[num_bytes] = '\0';
-
-      result_utf8 = mb_to_utf8 (context_xim, buffer);
-      if (result_utf8)
-       {
-         if ((guchar)result_utf8[0] >= 0x20 &&
-             result_utf8[0] != 0x7f) /* Some IM have a nasty habit of converting
-                                      * control characters into strings
-                                      */
-           {
-             g_signal_emit_by_name (context, "commit", result_utf8);
-             result = TRUE;
-           }
-         
-         g_free (result_utf8);
-       }
-    }
-
-  if (buffer != static_buffer) 
-    g_free (buffer);
-
-  return result;
-}
-
-static void
-gtk_im_context_xim_focus_in (GtkIMContext *context)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-
-  if (!context_xim->has_focus)
-    {
-      XIC ic = gtk_im_context_xim_get_ic (context_xim);
-
-      context_xim->has_focus = TRUE;
-      update_status_window (context_xim);
-      
-      if (ic)
-       XSetICFocus (ic);
-    }
-
-  return;
-}
-
-static void
-gtk_im_context_xim_focus_out (GtkIMContext *context)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-
-  if (context_xim->has_focus)
-    {
-      XIC ic = gtk_im_context_xim_get_ic (context_xim);
-      
-      context_xim->has_focus = FALSE;
-      update_status_window (context_xim);
-  
-      if (ic)
-       XUnsetICFocus (ic);
-    }
-
-  return;
-}
-
-static void
-gtk_im_context_xim_set_cursor_location (GtkIMContext *context,
-                                       GdkRectangle *area)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  XIC ic = gtk_im_context_xim_get_ic (context_xim);
-
-  XVaNestedList preedit_attr;
-  XPoint          spot;
-
-  if (!ic)
-    return;
-
-  spot.x = area->x;
-  spot.y = area->y + area->height;
-
-  preedit_attr = XVaCreateNestedList (0,
-                                     XNSpotLocation, &spot,
-                                     NULL);
-  XSetICValues (ic,
-               XNPreeditAttributes, preedit_attr,
-               NULL);
-  XFree(preedit_attr);
-
-  return;
-}
-
-static void
-gtk_im_context_xim_set_use_preedit (GtkIMContext *context,
-                                   gboolean      use_preedit)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-
-  use_preedit = use_preedit != FALSE;
-
-  if (context_xim->use_preedit != use_preedit)
-    {
-      context_xim->use_preedit = use_preedit;
-      reinitialize_ic (context_xim);
-    }
-
-  return;
-}
-
-static void
-gtk_im_context_xim_reset (GtkIMContext *context)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  XIC ic = gtk_im_context_xim_get_ic (context_xim);
-  gchar *result;
-
-  /* restore conversion state after resetting ic later */
-  XIMPreeditState preedit_state = XIMPreeditUnKnown;
-  XVaNestedList preedit_attr;
-  gboolean have_preedit_state = FALSE;
-
-  if (!ic)
-    return;
-  
-
-  if (context_xim->preedit_length == 0)
-    return;
-
-  preedit_attr = XVaCreateNestedList(0,
-                                     XNPreeditState, &preedit_state,
-                                     NULL);
-  if (!XGetICValues(ic,
-                    XNPreeditAttributes, preedit_attr,
-                    NULL))
-    have_preedit_state = TRUE;
-
-  XFree(preedit_attr);
-
-  result = XmbResetIC (ic);
-
-  preedit_attr = XVaCreateNestedList(0,
-                                     XNPreeditState, preedit_state,
-                                     NULL);
-  if (have_preedit_state)
-    XSetICValues(ic,
-                XNPreeditAttributes, preedit_attr,
-                NULL);
-
-  XFree(preedit_attr);
-
-  if (result)
-    {
-      char *result_utf8 = mb_to_utf8 (context_xim, result);
-      if (result_utf8)
-       {
-         g_signal_emit_by_name (context, "commit", result_utf8);
-         g_free (result_utf8);
-       }
-    }
-
-  if (context_xim->preedit_length)
-    {
-      context_xim->preedit_length = 0;
-      g_signal_emit_by_name (context, "preedit-changed");
-    }
-
-  XFree (result);
-}
-
-/* Mask of feedback bits that we render
- */
-#define FEEDBACK_MASK (XIMReverse | XIMUnderline)
-
-static void
-add_feedback_attr (PangoAttrList *attrs,
-                  const gchar   *str,
-                  XIMFeedback    feedback,
-                  gint           start_pos,
-                  gint           end_pos)
-{
-  PangoAttribute *attr;
-  
-  gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str;
-  gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str;
-
-  if (feedback & XIMUnderline)
-    {
-      attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
-      attr->start_index = start_index;
-      attr->end_index = end_index;
-
-      pango_attr_list_change (attrs, attr);
-    }
-
-  if (feedback & XIMReverse)
-    {
-      attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
-      attr->start_index = start_index;
-      attr->end_index = end_index;
-
-      pango_attr_list_change (attrs, attr);
-
-      attr = pango_attr_background_new (0, 0, 0);
-      attr->start_index = start_index;
-      attr->end_index = end_index;
-
-      pango_attr_list_change (attrs, attr);
-    }
-
-  if (feedback & ~FEEDBACK_MASK)
-    g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK);
-}
-
-static void     
-gtk_im_context_xim_get_preedit_string (GtkIMContext   *context,
-                                      gchar         **str,
-                                      PangoAttrList **attrs,
-                                      gint           *cursor_pos)
-{
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  gchar *utf8 = g_ucs4_to_utf8 (context_xim->preedit_chars, context_xim->preedit_length, NULL, NULL, NULL);
-
-  if (attrs)
-    {
-      int i;
-      XIMFeedback last_feedback = 0;
-      gint start = -1;
-      
-      *attrs = pango_attr_list_new ();
-
-      for (i = 0; i < context_xim->preedit_length; i++)
-       {
-         XIMFeedback new_feedback = context_xim->feedbacks[i] & FEEDBACK_MASK;
-         if (new_feedback != last_feedback)
-           {
-             if (start >= 0)
-               add_feedback_attr (*attrs, utf8, last_feedback, start, i);
-             
-             last_feedback = new_feedback;
-             start = i;
-           }
-       }
-
-      if (start >= 0)
-       add_feedback_attr (*attrs, utf8, last_feedback, start, i);
-    }
-
-  if (str)
-    *str = utf8;
-  else
-    g_free (utf8);
-
-  if (cursor_pos)
-    *cursor_pos = context_xim->preedit_cursor;
-}
-
-static int
-preedit_start_callback (XIC      xic,
-                       XPointer client_data,
-                       XPointer call_data)
-{
-  GtkIMContext *context = GTK_IM_CONTEXT (client_data);
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-  
-  if (!context_xim->finalizing)
-    g_signal_emit_by_name (context, "preedit-start");
-
-  return -1;                   /* No length limit */
-}                   
-
-static void
-preedit_done_callback (XIC      xic,
-                    XPointer client_data,
-                    XPointer call_data)
-{
-  GtkIMContext *context = GTK_IM_CONTEXT (client_data);
-  GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
-
-  if (context_xim->preedit_length)
-    {
-      context_xim->preedit_length = 0;
-      if (!context_xim->finalizing)
-       g_signal_emit_by_name (context_xim, "preedit-changed");
-    }
-
-  if (!context_xim->finalizing)
-    g_signal_emit_by_name (context, "preedit-end");
-}                   
-
-static gint
-xim_text_to_utf8 (GtkIMContextXIM *context, XIMText *xim_text, gchar **text)
-{
-  gint text_length = 0;
-  GError *error = NULL;
-  gchar *result = NULL;
-
-  if (xim_text && xim_text->string.multi_byte)
-    {
-      if (xim_text->encoding_is_wchar)
-       {
-         g_warning ("Wide character return from Xlib not currently supported");
-         *text = NULL;
-         return 0;
-       }
-
-      if (strcmp (context->mb_charset, "UTF-8") == 0)
-       result = g_strdup (xim_text->string.multi_byte);
-      else
-       result = g_convert (xim_text->string.multi_byte,
-                           -1,
-                           "UTF-8",
-                           context->mb_charset,
-                           NULL, NULL, &error);
-      
-      if (result)
-       {
-         text_length = g_utf8_strlen (result, -1);
-         
-         if (text_length != xim_text->length)
-           {
-             g_warning ("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
-           }
-       }
-      else
-       {
-         g_warning ("Error converting text from IM to UCS-4: %s", error->message);
-         g_error_free (error);
-
-         *text = NULL;
-         return 0;
-       }
-
-      *text = result;
-      return text_length;
-    }
-  else
-    {
-      *text = NULL;
-      return 0;
-    }
-}
-
-static void
-preedit_draw_callback (XIC                           xic, 
-                      XPointer                      client_data,
-                      XIMPreeditDrawCallbackStruct *call_data)
-{
-  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
-
-  XIMText *new_xim_text = call_data->text;
-  gint new_text_length;
-  gunichar *new_text = NULL;
-  gint i;
-  gint diff;
-  gint new_length;
-  gchar *tmp;
-  
-  gint chg_first = CLAMP (call_data->chg_first, 0, context->preedit_length);
-  gint chg_length = CLAMP (call_data->chg_length, 0, context->preedit_length - chg_first);
-
-  context->preedit_cursor = call_data->caret;
-  
-  if (chg_first != call_data->chg_first || chg_length != call_data->chg_length)
-    g_warning ("Invalid change to preedit string, first=%d length=%d (orig length == %d)",
-              call_data->chg_first, call_data->chg_length, context->preedit_length);
-
-  new_text_length = xim_text_to_utf8 (context, new_xim_text, &tmp);
-  if (tmp)
-    {
-      new_text = g_utf8_to_ucs4_fast (tmp, -1, NULL);
-      g_free (tmp);
-    }
-  
-  diff = new_text_length - chg_length;
-  new_length = context->preedit_length + diff;
-
-  if (new_length > context->preedit_size)
-    {
-      context->preedit_size = new_length;
-      context->preedit_chars = g_renew (gunichar, context->preedit_chars, new_length);
-      context->feedbacks = g_renew (XIMFeedback, context->feedbacks, new_length);
-    }
-
-  if (diff < 0)
-    {
-      for (i = chg_first + chg_length ; i < context->preedit_length; i++)
-       {
-         context->preedit_chars[i + diff] = context->preedit_chars[i];
-         context->feedbacks[i + diff] = context->feedbacks[i];
-       }
-    }
-  else
-    {
-      for (i = context->preedit_length - 1; i >= chg_first + chg_length ; i--)
-       {
-         context->preedit_chars[i + diff] = context->preedit_chars[i];
-         context->feedbacks[i + diff] = context->feedbacks[i];
-       }
-    }
-
-  for (i = 0; i < new_text_length; i++)
-    {
-      context->preedit_chars[chg_first + i] = new_text[i];
-      context->feedbacks[chg_first + i] = new_xim_text->feedback[i];
-    }
-
-  context->preedit_length += diff;
-
-  g_free (new_text);
-
-  if (!context->finalizing)
-    g_signal_emit_by_name (context, "preedit-changed");
-}
-    
-
-static void
-preedit_caret_callback (XIC                            xic,
-                       XPointer                       client_data,
-                       XIMPreeditCaretCallbackStruct *call_data)
-{
-  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
-  
-  if (call_data->direction == XIMAbsolutePosition)
-    {
-      context->preedit_cursor = call_data->position;
-      if (!context->finalizing)
-       g_signal_emit_by_name (context, "preedit-changed");
-    }
-  else
-    {
-      g_warning ("Caret movement command: %d %d %d not supported",
-                call_data->position, call_data->direction, call_data->style);
-    }
-}           
-
-static void
-status_start_callback (XIC      xic,
-                      XPointer client_data,
-                      XPointer call_data)
-{
-  return;
-} 
-
-static void
-status_done_callback (XIC      xic,
-                     XPointer client_data,
-                     XPointer call_data)
-{
-  return;
-}
-
-static void
-status_draw_callback (XIC      xic,
-                     XPointer client_data,
-                     XIMStatusDrawCallbackStruct *call_data)
-{
-  GtkIMContextXIM *context = GTK_IM_CONTEXT_XIM (client_data);
-
-  if (call_data->type == XIMTextType)
-    {
-      gchar *text;
-      xim_text_to_utf8 (context, call_data->data.text, &text);
-
-      if (context->status_window)
-       status_window_set_text (context->status_window, text ? text : "");
-    }
-  else                         /* bitmap */
-    {
-      g_print ("Status drawn with bitmap - id = %#lx\n", call_data->data.bitmap);
-    }
-}
-
-static void
-string_conversion_callback (XIC xic, XPointer client_data, XPointer call_data)
-{
-  GtkIMContextXIM *context_xim;
-  XIMStringConversionCallbackStruct *conv_data;
-  gchar *surrounding;
-  gint  cursor_index;
-
-  context_xim = (GtkIMContextXIM *)client_data;
-  conv_data = (XIMStringConversionCallbackStruct *)call_data;
-
-  if (gtk_im_context_get_surrounding ((GtkIMContext *)context_xim,
-                                      &surrounding, &cursor_index))
-    {
-      gchar *text = NULL;
-      gsize text_len = 0;
-      gint  subst_offset = 0, subst_nchars = 0;
-      gint  i;
-      gchar *p = surrounding + cursor_index, *q;
-      gshort position = (gshort)conv_data->position;
-
-      if (position > 0)
-        {
-          for (i = position; i > 0 && *p; --i)
-            p = g_utf8_next_char (p);
-          if (i > 0)
-            return;
-        }
-      /* According to X11R6.4 Xlib - C Library Reference Manual
-       * section 13.5.7.3 String Conversion Callback,
-       * XIMStringConversionPosition is starting position _relative_
-       * to current client's cursor position. So it should be able
-       * to be negative, or referring to a position before the cursor
-       * would be impossible. But current X protocol defines this as
-       * unsigned short. So, compiler may warn about the value range
-       * here. We hope the X protocol is fixed soon.
-       */
-      else if (position < 0)
-        {
-          for (i = position; i < 0 && p > surrounding; ++i)
-            p = g_utf8_prev_char (p);
-          if (i < 0)
-            return;
-        }
-
-      switch (conv_data->direction)
-        {
-        case XIMForwardChar:
-          for (i = conv_data->factor, q = p; i > 0 && *q; --i)
-            q = g_utf8_next_char (q);
-          if (i > 0)
-            break;
-          text = g_locale_from_utf8 (p, q - p, NULL, &text_len, NULL);
-          subst_offset = position;
-          subst_nchars = conv_data->factor;
-          break;
-
-        case XIMBackwardChar:
-          for (i = conv_data->factor, q = p; i > 0 && q > surrounding; --i)
-            q = g_utf8_prev_char (q);
-          if (i > 0)
-            break;
-          text = g_locale_from_utf8 (q, p - q, NULL, &text_len, NULL);
-          subst_offset = position - conv_data->factor;
-          subst_nchars = conv_data->factor;
-          break;
-
-        case XIMForwardWord:
-        case XIMBackwardWord:
-        case XIMCaretUp:
-        case XIMCaretDown:
-        case XIMNextLine:
-        case XIMPreviousLine:
-        case XIMLineStart:
-        case XIMLineEnd:
-        case XIMAbsolutePosition:
-        case XIMDontChange:
-        default:
-          break;
-        }
-      /* block out any failure happenning to "text", including conversion */
-      if (text)
-        {
-          conv_data->text = (XIMStringConversionText *)
-                              malloc (sizeof (XIMStringConversionText));
-          if (conv_data->text)
-            {
-              conv_data->text->length = text_len;
-              conv_data->text->feedback = NULL;
-              conv_data->text->encoding_is_wchar = False;
-              conv_data->text->string.mbs = (char *)malloc (text_len);
-              if (conv_data->text->string.mbs)
-                memcpy (conv_data->text->string.mbs, text, text_len);
-              else
-                {
-                  free (conv_data->text);
-                  conv_data->text = NULL;
-                }
-            }
-
-          g_free (text);
-        }
-      if (conv_data->operation == XIMStringConversionSubstitution
-          && subst_nchars > 0)
-        {
-          gtk_im_context_delete_surrounding ((GtkIMContext *)context_xim,
-                                            subst_offset, subst_nchars);
-        }
-
-      g_free (surrounding);
-    }
-}
-
-
-static XVaNestedList
-set_preedit_callback (GtkIMContextXIM *context_xim)
-{
-  context_xim->preedit_start_callback.client_data = (XPointer)context_xim;
-  context_xim->preedit_start_callback.callback = (XIMProc)preedit_start_callback;
-  context_xim->preedit_done_callback.client_data = (XPointer)context_xim;
-  context_xim->preedit_done_callback.callback = (XIMProc)preedit_done_callback;
-  context_xim->preedit_draw_callback.client_data = (XPointer)context_xim;
-  context_xim->preedit_draw_callback.callback = (XIMProc)preedit_draw_callback;
-  context_xim->preedit_caret_callback.client_data = (XPointer)context_xim;
-  context_xim->preedit_caret_callback.callback = (XIMProc)preedit_caret_callback;
-  return XVaCreateNestedList (0,
-                             XNPreeditStartCallback, &context_xim->preedit_start_callback,
-                             XNPreeditDoneCallback, &context_xim->preedit_done_callback,
-                             XNPreeditDrawCallback, &context_xim->preedit_draw_callback,
-                             XNPreeditCaretCallback, &context_xim->preedit_caret_callback,
-                             NULL);
-}
-
-static XVaNestedList
-set_status_callback (GtkIMContextXIM *context_xim)
-{
-  context_xim->status_start_callback.client_data = (XPointer)context_xim;
-  context_xim->status_start_callback.callback = (XIMProc)status_start_callback;
-  context_xim->status_done_callback.client_data = (XPointer)context_xim;
-  context_xim->status_done_callback.callback = (XIMProc)status_done_callback;
-  context_xim->status_draw_callback.client_data = (XPointer)context_xim;
-  context_xim->status_draw_callback.callback = (XIMProc)status_draw_callback;
-         
-  return XVaCreateNestedList (0,
-                             XNStatusStartCallback, &context_xim->status_start_callback,
-                             XNStatusDoneCallback, &context_xim->status_done_callback,
-                             XNStatusDrawCallback, &context_xim->status_draw_callback,
-                             NULL);
-}
-
-
-static void
-set_string_conversion_callback (GtkIMContextXIM *context_xim, XIC xic)
-{
-  if (!context_xim->im_info->supports_string_conversion)
-    return;
-  
-  context_xim->string_conversion_callback.client_data = (XPointer)context_xim;
-  context_xim->string_conversion_callback.callback = (XIMProc)string_conversion_callback;
-  
-  XSetICValues (xic,
-               XNStringConversionCallback,
-               (XPointer)&context_xim->string_conversion_callback,
-               NULL);
-}
-
-static XIC
-gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
-{
-  if (context_xim->im_info == NULL || context_xim->im_info->im == NULL)
-    return NULL;
-
-  if (!context_xim->ic)
-    {
-      const char *name1 = NULL;
-      XVaNestedList list1 = NULL;
-      const char *name2 = NULL;
-      XVaNestedList list2 = NULL;
-      XIMStyle im_style = 0;
-      XIC xic = NULL;
-
-      if (context_xim->use_preedit &&
-         (context_xim->im_info->style & PREEDIT_MASK) == XIMPreeditCallbacks)
-       {
-         im_style |= XIMPreeditCallbacks;
-         name1 = XNPreeditAttributes;
-         list1 = set_preedit_callback (context_xim);
-       }
-      else if ((context_xim->im_info->style & PREEDIT_MASK) == XIMPreeditNone)
-       im_style |= XIMPreeditNone;
-      else
-       im_style |= XIMPreeditNothing;
-
-      if ((context_xim->im_info->style & STATUS_MASK) == XIMStatusCallbacks)
-       {
-         im_style |= XIMStatusCallbacks;
-         if (name1 == NULL)
-           {
-             name1 = XNStatusAttributes;
-             list1 = set_status_callback (context_xim);
-           }
-         else
-           {
-             name2 = XNStatusAttributes;
-             list2 = set_status_callback (context_xim);
-           }
-       }
-      else if ((context_xim->im_info->style & STATUS_MASK) == XIMStatusNone)
-       im_style |= XIMStatusNone;
-      else
-       im_style |= XIMStatusNothing;
-
-      xic = XCreateIC (context_xim->im_info->im,
-                      XNInputStyle, im_style,
-                      XNClientWindow, context_xim->client_window_xid,
-                      name1, list1,
-                      name2, list2,
-                      NULL);
-      if (list1)
-       XFree (list1);
-      if (list2)
-       XFree (list2);
-
-      if (xic)
-       {
-         /* Don't filter key released events with XFilterEvents unless
-          * input methods ask for. This is a workaround for Solaris input
-          * method bug in C and European locales. It doubles each key
-          * stroke if both key pressed and released events are filtered.
-          * (bugzilla #81759)
-          */
-         gulong mask = 0xaaaaaaaa;
-         XGetICValues (xic,
-                       XNFilterEvents, &mask,
-                       NULL);
-         context_xim->filter_key_release = (mask & KeyReleaseMask) != 0;
-         set_string_conversion_callback (context_xim, xic);
-       }
-      
-      context_xim->ic = xic;
-
-      update_status_window (context_xim);
-      
-      if (xic && context_xim->has_focus)
-       XSetICFocus (xic);
-    }
-  return context_xim->ic;
-}
-
-/*****************************************************************
- * Status Window handling
- *
- * A status window is a small window attached to the toplevel
- * that is used to display information to the user about the
- * current input operation.
- *
- * We claim the toplevel's status window for an input context if:
- *
- * A) The input context has a toplevel
- * B) The input context has the focus
- * C) The input context has an XIC associated with it
- *
- * Tracking A) and C) is pretty reliable since we
- * compute A) and create the XIC for C) ourselves.
- * For B) we basically have to depend on our callers
- * calling ::focus-in and ::focus-out at the right time.
- *
- * The toplevel is computed by walking up the GdkWindow
- * hierarchy from context->client_window until we find a
- * window that is owned by some widget, and then calling
- * gtk_widget_get_toplevel() on that widget. This should
- * handle both cases where we might have GdkWindows without widgets,
- * and cases where GtkWidgets have strange window hierarchies
- * (like a torn off GtkHandleBox.)
- *
- * The status window is visible if and only if there is text
- * for it; whenever a new GtkIMContextXIM claims the status
- * window, we blank out any existing text. We actually only
- * create a GtkWindow for the status window the first time
- * it is shown; this is an important optimization when we are
- * using XIM with something like a simple compose-key input
- * method that never needs a status window.
- *****************************************************************/
-
-/* Called when we no longer need a status window
-*/
-static void
-disclaim_status_window (GtkIMContextXIM *context_xim)
-{
-  if (context_xim->status_window)
-    {
-      g_assert (context_xim->status_window->context == context_xim);
-
-      status_window_set_text (context_xim->status_window, "");
-      
-      context_xim->status_window->context = NULL;
-      context_xim->status_window = NULL;
-    }
-}
-
-/* Called when we need a status window
- */
-static void
-claim_status_window (GtkIMContextXIM *context_xim)
-{
-  if (!context_xim->status_window && context_xim->client_widget)
-    {
-      GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
-      if (toplevel && gtk_widget_is_toplevel (toplevel))
-       {
-         StatusWindow *status_window = status_window_get (toplevel);
-
-         if (status_window->context)
-           disclaim_status_window (status_window->context);
-
-         status_window->context = context_xim;
-         context_xim->status_window = status_window;
-       }
-    }
-}
-
-/* Basic call made whenever something changed that might cause
- * us to need, or not to need a status window.
- */
-static void
-update_status_window (GtkIMContextXIM *context_xim)
-{
-  if (context_xim->ic && context_xim->in_toplevel && context_xim->has_focus)
-    claim_status_window (context_xim);
-  else
-    disclaim_status_window (context_xim);
-}
-
-/* Updates the in_toplevel flag for @context_xim
- */
-static void
-update_in_toplevel (GtkIMContextXIM *context_xim)
-{
-  if (context_xim->client_widget)
-    {
-      GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
-      
-      context_xim->in_toplevel = (toplevel && gtk_widget_is_toplevel (toplevel));
-    }
-  else
-    context_xim->in_toplevel = FALSE;
-
-  /* Some paranoia, in case we don't get a focus out */
-  if (!context_xim->in_toplevel)
-    context_xim->has_focus = FALSE;
-  
-  update_status_window (context_xim);
-}
-
-/* Callback when @widget's toplevel changes. It will always
- * change from NULL to a window, or a window to NULL;
- * we use that intermediate NULL state to make sure
- * that we disclaim the toplevel status window for the old
- * window.
- */
-static void
-on_client_widget_hierarchy_changed (GtkWidget       *widget,
-                                   GtkWidget       *old_toplevel,
-                                   GtkIMContextXIM *context_xim)
-{
-  update_in_toplevel (context_xim);
-}
-
-/* Finds the GtkWidget that owns the window, or if none, the
- * widget owning the nearest parent that has a widget.
- */
-static GtkWidget *
-widget_for_window (GdkWindow *window)
-{
-  while (window)
-    {
-      gpointer user_data;
-      gdk_window_get_user_data (window, &user_data);
-      if (user_data)
-       return user_data;
-
-      window = gdk_window_get_parent (window);
-    }
-
-  return NULL;
-}
-
-/* Called when context_xim->client_window changes; takes care of
- * removing and/or setting up our watches for the toplevel
- */
-static void
-update_client_widget (GtkIMContextXIM *context_xim)
-{
-  GtkWidget *new_client_widget = widget_for_window (context_xim->client_window);
-
-  if (new_client_widget != context_xim->client_widget)
-    {
-      if (context_xim->client_widget)
-       {
-         g_signal_handlers_disconnect_by_func (context_xim->client_widget,
-                                               G_CALLBACK (on_client_widget_hierarchy_changed),
-                                               context_xim);
-       }
-      context_xim->client_widget = new_client_widget;
-      if (context_xim->client_widget)
-       {
-         g_signal_connect (context_xim->client_widget, "hierarchy-changed",
-                           G_CALLBACK (on_client_widget_hierarchy_changed),
-                           context_xim);
-       }
-
-      update_in_toplevel (context_xim);
-    }
-}
-
-/* Called when the toplevel is destroyed; frees the status window
- */
-static void
-on_status_toplevel_destroy (GtkWidget    *toplevel,
-                           StatusWindow *status_window)
-{
-  status_window_free (status_window);
-}
-
-/* Called when the screen for the toplevel changes; updates the
- * screen for the status window to match.
- */
-static void
-on_status_toplevel_notify_display (GtkWindow    *toplevel,
-                                  GParamSpec   *pspec,
-                                  StatusWindow *status_window)
-{
-  if (status_window->window)
-    gtk_window_set_display (GTK_WINDOW (status_window->window),
-                           gtk_widget_get_display (GTK_WIDGET (toplevel)));
-}
-
-/* Called when the toplevel window is moved; updates the position of
- * the status window to follow it.
- */
-static gboolean
-on_status_toplevel_configure (GtkWidget     *toplevel,
-                             GdkEvent      *event,
-                             StatusWindow  *status_window)
-{
-  if (gdk_event_get_event_type (event) == GDK_CONFIGURE)
-    {
-      GdkRectangle rect;
-      GtkRequisition requisition;
-      gint y;
-      gint height;
-
-      if (status_window->window)
-        {
-          height = DisplayHeight(GDK_WINDOW_XDISPLAY (gtk_widget_get_window (toplevel)), 0);
-
-          gdk_window_get_frame_extents (gtk_widget_get_window (toplevel), &rect);
-          gtk_widget_get_preferred_size ( (status_window->window), &requisition, NULL);
-
-          if (rect.y + rect.height + requisition.height < height)
-           y = rect.y + rect.height;
-          else
-           y = height - requisition.height;
-
-          gtk_window_move (GTK_WINDOW (status_window->window), rect.x, y);
-        }
-    }
-
-  return GDK_EVENT_PROPAGATE;
-}
-
-/* Frees a status window and removes its link from the status_windows list
- */
-static void
-status_window_free (StatusWindow *status_window)
-{
-  status_windows = g_slist_remove (status_windows, status_window);
-
-  if (status_window->context)
-    status_window->context->status_window = NULL;
-  g_signal_handlers_disconnect_by_func (status_window->toplevel,
-                                       G_CALLBACK (on_status_toplevel_destroy),
-                                       status_window);
-  g_signal_handlers_disconnect_by_func (status_window->toplevel,
-                                       G_CALLBACK (on_status_toplevel_notify_display),
-                                       status_window);
-  g_signal_handlers_disconnect_by_func (status_window->toplevel,
-                                       G_CALLBACK (on_status_toplevel_configure),
-                                       status_window);
-
-  if (status_window->window)
-    gtk_widget_destroy (status_window->window);
-  
-  g_object_set_data (G_OBJECT (status_window->toplevel), "gtk-im-xim-status-window", NULL);
-  g_free (status_window);
-}
-
-/* Finds the status window object for a toplevel, creating it if necessary.
- */
-static StatusWindow *
-status_window_get (GtkWidget *toplevel)
-{
-  StatusWindow *status_window;
-
-  status_window = g_object_get_data (G_OBJECT (toplevel), "gtk-im-xim-status-window");
-  if (status_window)
-    return status_window;
-  
-  status_window = g_new0 (StatusWindow, 1);
-  status_window->toplevel = toplevel;
-
-  status_windows = g_slist_prepend (status_windows, status_window);
-
-  g_signal_connect (toplevel, "destroy",
-                   G_CALLBACK (on_status_toplevel_destroy),
-                   status_window);
-  g_signal_connect (toplevel, "event",
-                   G_CALLBACK (on_status_toplevel_configure),
-                   status_window);
-  g_signal_connect (toplevel, "notify::display",
-                   G_CALLBACK (on_status_toplevel_notify_display),
-                   status_window);
-  
-  g_object_set_data (G_OBJECT (toplevel), "gtk-im-xim-status-window", status_window);
-
-  return status_window;
-}
-
-/* Creates the widgets for the status window; called when we
- * first need to show text for the status window.
- */
-static void
-status_window_make_window (StatusWindow *status_window)
-{
-  GtkWidget *window;
-  GtkWidget *status_label;
-  
-  status_window->window = gtk_window_new (GTK_WINDOW_POPUP);
-  window = status_window->window;
-
-  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
-
-  status_label = gtk_label_new ("");
-  g_object_set (status_label, "margin", 1, NULL);
-  gtk_widget_show (status_label);
-  
-  gtk_container_add (GTK_CONTAINER (window), status_label);
-  
-  gtk_window_set_display (GTK_WINDOW (status_window->window),
-                         gtk_widget_get_display (status_window->toplevel));
-
-  on_status_toplevel_configure (status_window->toplevel, NULL, status_window);
-}
-
-/* Updates the text in the status window, hiding or
- * showing the window as necessary.
- */
-static void
-status_window_set_text (StatusWindow *status_window,
-                       const gchar  *text)
-{
-  if (text[0])
-    {
-      GtkWidget *label;
-      
-      if (!status_window->window)
-       status_window_make_window (status_window);
-      
-      label = gtk_bin_get_child (GTK_BIN (status_window->window));
-      gtk_label_set_text (GTK_LABEL (label), text);
-  
-      gtk_widget_show (status_window->window);
-    }
-  else
-    {
-      if (status_window->window)
-       gtk_widget_hide (status_window->window);
-    }
-}
-
-/**
- * gtk_im_context_xim_shutdown:
- * 
- * Destroys all the status windows that are kept by the XIM contexts.  This
- * function should only be called by the XIM module exit routine.
- **/
-void
-gtk_im_context_xim_shutdown (void)
-{
-  while (status_windows)
-    status_window_free (status_windows->data);
-
-  while (open_ims)
-    {
-      GtkXIMInfo *info = open_ims->data;
-      GdkDisplay *display = info->display;
-
-      xim_info_display_closed (display, FALSE, info);
-      open_ims = g_slist_remove_link (open_ims, open_ims);
-    }
-}
diff --git a/modules/input/gtkimcontextxim.h b/modules/input/gtkimcontextxim.h
deleted file mode 100644 (file)
index d81a7ff..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) 2000 Red Hat Software
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GTK_IM_CONTEXT_XIM_H__
-#define __GTK_IM_CONTEXT_XIM_H__
-
-#include <gtk/gtk.h>
-#include "x11/gdkx.h"
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_IM_CONTEXT_XIM            (gtk_im_context_xim_get_type ())
-#define GTK_IM_CONTEXT_XIM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIM))
-#define GTK_IM_CONTEXT_XIM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))
-#define GTK_IS_IM_CONTEXT_XIM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_IM_CONTEXT_XIM))
-#define GTK_IS_IM_CONTEXT_XIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_IM_CONTEXT_XIM))
-#define GTK_IM_CONTEXT_XIM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_IM_CONTEXT_XIM, GtkIMContextXIMClass))
-
-
-typedef struct _GtkIMContextXIM       GtkIMContextXIM;
-typedef struct _GtkIMContextXIMClass  GtkIMContextXIMClass;
-
-struct _GtkIMContextXIMClass
-{
-  GtkIMContextClass parent_class;
-};
-
-GtkIMContext *gtk_im_context_xim_new (void);
-
-void gtk_im_context_xim_shutdown (void);
-
-G_END_DECLS
-
-#endif /* __GTK_IM_CONTEXT_XIM_H__ */
diff --git a/modules/input/imbroadway.c b/modules/input/imbroadway.c
deleted file mode 100644 (file)
index 2fb40d4..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * gtkimmodulebroadway
- * Copyright (C) 2013 Alexander Larsson
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * $Id:$
- */
-
-#include "config.h"
-#include <string.h>
-
-#include <gtk/gtk.h>
-#include "gtk/gtkintl.h"
-#include "gtk/gtkimmodule.h"
-
-#include "gdk/broadway/gdkbroadway.h"
-
-#define GTK_TYPE_IM_CONTEXT_BROADWAY (gtk_im_context_broadway_get_type ())
-#define GTK_IM_CONTEXT_BROADWAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_BROADWAY, GtkIMContextBroadway))
-#define GTK_IM_CONTEXT_BROADWAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_IM_CONTEXT_BROADWAY, GtkIMContextBroadwayClass))
-
-typedef struct _GtkIMContextBroadway
-{
-  GtkIMContextSimple parent;
-  GtkWidget *client_widget;
-} GtkIMContextBroadway;
-
-typedef struct _GtkIMContextBroadwayClass
-{
-  GtkIMContextSimpleClass parent_class;
-} GtkIMContextBroadwayClass;
-
-G_DEFINE_DYNAMIC_TYPE (GtkIMContextBroadway, gtk_im_context_broadway, GTK_TYPE_IM_CONTEXT_SIMPLE)
-
-void
-g_io_module_load (GIOModule *module)
-{
-  g_type_module_use (G_TYPE_MODULE (module));
-
-  g_print ("load io module for broadway\n");
-  gtk_im_context_broadway_register_type (G_TYPE_MODULE (module));
-
-  g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
-                                  GTK_TYPE_IM_CONTEXT_BROADWAY,
-                                  "broadway",
-                                  10);
-}
-
-void
-g_io_module_unload (GIOModule *module)
-{
-}
-
-char **
-g_io_module_query (void)
-{
-  char *eps[] = {
-    GTK_IM_MODULE_EXTENSION_POINT_NAME,
-    NULL
-  };
-
-  return g_strdupv (eps);
-}
-
-
-static void
-broadway_set_client_widget (GtkIMContext *context, GtkWidget *widget)
-{
-  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
-
-  bw->client_widget = widget;
-}
-
-static void
-broadway_focus_in (GtkIMContext *context)
-{
-  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
-  GdkDisplay *display;
-
-  if (bw->client_widget)
-    {
-      display = gtk_widget_get_display (bw->client_widget);
-      gdk_broadway_display_show_keyboard (GDK_BROADWAY_DISPLAY (display));
-    }
-}
-
-static void
-broadway_focus_out (GtkIMContext *context)
-{
-  GtkIMContextBroadway *bw = GTK_IM_CONTEXT_BROADWAY (context);
-  GdkDisplay *display;
-
-  if (bw->client_widget)
-    {
-      display = gtk_widget_get_display (bw->client_widget);
-      gdk_broadway_display_hide_keyboard (GDK_BROADWAY_DISPLAY (display));
-    }
-}
-
-static void
-gtk_im_context_broadway_class_init (GtkIMContextBroadwayClass *class)
-{
-  GtkIMContextClass *klass = GTK_IM_CONTEXT_CLASS (class);
-
-  klass->focus_in = broadway_focus_in;
-  klass->focus_out = broadway_focus_out;
-  klass->set_client_widget = broadway_set_client_widget;
-}
-
-static void
-gtk_im_context_broadway_class_finalize (GtkIMContextBroadwayClass *class)
-{
-}
-
-static void
-gtk_im_context_broadway_init (GtkIMContextBroadway *im_context)
-{
-}
diff --git a/modules/input/imm-extra.h b/modules/input/imm-extra.h
deleted file mode 100644 (file)
index 094dc5b..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2003 Takuro Ashie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * $Id$ 
- */
-
-#include <windows.h>
-#include <imm.h>
-
-
-/* these aren't defined in Cygwin's imm.h */
-
-#ifndef WM_IME_REQUEST
-#   define WM_IME_REQUEST                  0x0288
-#endif  /* WM_IME_REQUEST */
-
-#ifndef IMR_COMPOSITIONWINDOW
-#   define IMR_COMPOSITIONWINDOW           0x0001
-#endif /* IMR_COMPOSITIONWINDOW */
-
-#ifndef IMR_CANDIDATEWINDOW
-#   define IMR_CANDIDATEWINDOW             0x0002
-#endif /* IMR_CANDIDATEWINDOW */
-
-#ifndef IMR_COMPOSITIONFONT
-#   define IMR_COMPOSITIONFONT             0x0003
-#endif /* IMR_COMPOSITIONFONT */
-
-#ifndef IMR_RECONVERTSTRING
-#   define IMR_RECONVERTSTRING             0x0004
-#endif /* IMR_RECONVERTSTRING */
-
-#ifndef IMR_CONFIRMRECONVERTSTRING
-#   define IMR_CONFIRMRECONVERTSTRING      0x0005
-#endif /* IMR_CONFIRMRECONVERTSTRING */
-
-#ifndef IMR_QUERYCHARPOSITION
-#   define IMR_QUERYCHARPOSITION           0x0006
-typedef struct tagIMECHARPOSITION {
-  DWORD  dwSize;
-  DWORD  dwCharPos;
-  POINT  pt;
-  UINT   cLineHeight;
-  RECT   rcDocument;
-} IMECHARPOSITION, *PIMECHARPOSITION;
-#endif /* IMR_QUERYCHARPOSITION */
-
-#ifndef IMR_DOCUMENTFEED
-#   define IMR_DOCUMENTFEED                0x0007
-#endif /* IMR_DOCUMENTFEED */
diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
deleted file mode 100644 (file)
index 9d1a1cc..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * gtkimmodulequartz
- * Copyright (C) 2011 Hiroyuki Yamamoto
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * $Id:$
- */
-
-#include "config.h"
-#include <string.h>
-
-#include <gtk/gtk.h>
-#include "gtk/gtkintl.h"
-#include "gtk/gtkimmodule.h"
-
-#include "gdk/quartz/gdkquartz.h"
-#include "gdk/quartz/GdkQuartzView.h"
-
-#define GTK_IM_CONTEXT_TYPE_QUARTZ (type_quartz)
-#define GTK_IM_CONTEXT_QUARTZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, GtkIMContextQuartz))
-#define GTK_IM_CONTEXT_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, GtkIMContextQuartzClass))
-
-
-typedef struct _GtkIMContextQuartz
-{
-  GtkIMContext parent;
-  GtkIMContext *slave;
-  GdkWindow *client_window;
-  gchar *preedit_str;
-  unsigned int cursor_index;
-  unsigned int selected_len;
-  GdkRectangle *cursor_rect;
-  gboolean focused;
-} GtkIMContextQuartz;
-
-typedef struct _GtkIMContextQuartzClass
-{
-  GtkIMContextClass parent_class;
-} GtkIMContextQuartzClass;
-
-G_DEFINE_DYNAMIC_TYPE (GtkIMContextQuartz, gtk_im_context_quartz, GTK_TYPE_IM_CONTEXT)
-
-void
-g_io_module_load (GIOModule *module)
-{
-  g_type_module_use (G_TYPE_MODULE (module));
-
-  g_print ("load io module for quartz\n");
-  gtk_im_context_quartz_register_type (G_TYPE_MODULE (module));
-
-  g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
-                                  GTK_TYPE_IM_CONTEXT_BROADWAY,
-                                  "quartz",
-                                  10);
-}
-
-void
-g_io_module_unload (GIOModule *module)
-{
-}
-
-char **
-g_io_module_query (void)
-{
-  char *eps[] = {
-    GTK_IM_MODULE_EXTENSION_POINT_NAME,
-    NULL
-  };
-
-  return g_strdupv (eps);
-}
-
-
-
-
-
-static void
-quartz_get_preedit_string (GtkIMContext *context,
-                           gchar **str,
-                           PangoAttrList **attrs,
-                           gint *cursor_pos)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-
-  GTK_NOTE (MISC, g_print ("quartz_get_preedit_string\n"));
-
-  if (str)
-    *str = qc->preedit_str ? g_strdup (qc->preedit_str) : g_strdup ("");
-
-  if (attrs)
-    {
-      *attrs = pango_attr_list_new ();
-      int len = g_utf8_strlen (*str, -1);
-      gchar *ch = *str;
-      if (len > 0)
-        {
-          PangoAttribute *attr;
-          int i = 0;
-          for (;;)
-            {
-              gchar *s = ch;
-              ch = g_utf8_next_char (ch);
-
-              if (i >= qc->cursor_index &&
-                 i < qc->cursor_index + qc->selected_len)
-                attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
-              else
-                attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
-
-              attr->start_index = s - *str;
-              if (!*ch)
-                attr->end_index = attr->start_index + strlen (s);
-              else
-                attr->end_index = ch - *str;
-
-              pango_attr_list_change (*attrs, attr);
-
-              if (!*ch)
-                break;
-              i++;
-            }
-        }
-    }
-  if (cursor_pos)
-    *cursor_pos = qc->cursor_index;
-}
-
-static gboolean
-output_result (GtkIMContext *context,
-               GdkWindow *win)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-  gboolean retval = FALSE;
-  gchar *fixed_str, *marked_str;
-
-  fixed_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_INSERT_TEXT));
-  marked_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_MARKED_TEXT));
-  if (fixed_str)
-    {
-      GTK_NOTE (MISC, g_print ("tic-insert-text: %s\n", fixed_str));
-      g_free (qc->preedit_str);
-      qc->preedit_str = NULL;
-      g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT, NULL);
-      g_signal_emit_by_name (context, "commit", fixed_str);
-      g_signal_emit_by_name (context, "preedit_changed");
-
-      unsigned int filtered =
-          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
-                                               GIC_FILTER_KEY));
-      GTK_NOTE (MISC, g_print ("filtered, %d\n", filtered));
-      if (filtered)
-        retval = TRUE;
-      else
-        retval = FALSE;
-    }
-  if (marked_str)
-    {
-      GTK_NOTE (MISC, g_print ("tic-marked-text: %s\n", marked_str));
-      qc->cursor_index =
-          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
-                                               TIC_SELECTED_POS));
-      qc->selected_len =
-          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
-                                               TIC_SELECTED_LEN));
-      g_free (qc->preedit_str);
-      qc->preedit_str = g_strdup (marked_str);
-      g_object_set_data (G_OBJECT (win), TIC_MARKED_TEXT, NULL);
-      g_signal_emit_by_name (context, "preedit_changed");
-      retval = TRUE;
-    }
-  if (!fixed_str && !marked_str)
-    {
-      if (qc->preedit_str && strlen (qc->preedit_str) > 0)
-        retval = TRUE;
-    }
-  g_free (fixed_str);
-  g_free (marked_str);
-  return retval;
-}
-
-static gboolean
-quartz_filter_keypress (GtkIMContext *context,
-                        GdkEventKey *event)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-  gboolean retval;
-  NSView *nsview;
-  GdkWindow *win;
-
-  GTK_NOTE (MISC, g_print ("quartz_filter_keypress\n"));
-
-  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
-    return FALSE;
-
-  nsview = gdk_quartz_window_get_nsview (qc->client_window);
-  win = (GdkWindow *)[ (GdkQuartzView *)nsview gdkWindow];
-  GTK_NOTE (MISC, g_print ("client_window: %p, win: %p, nsview: %p\n",
-                          qc->client_window, win, nsview));
-
-  NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *)event);
-
-  if (!nsevent)
-    {
-      if (event->hardware_keycode == 0 && event->keyval == 0xffffff)
-        /* update text input changes by mouse events */
-        return output_result (context, win);
-      else
-        return gtk_im_context_filter_keypress (qc->slave, event);
-    }
-
-  if (event->type == GDK_KEY_RELEASE)
-    return FALSE;
-
-  if (event->hardware_keycode == 55)   /* Command */
-    return FALSE;
-
-  NSEventType etype = [nsevent type];
-  if (etype == NSKeyDown)
-    {
-       g_object_set_data (G_OBJECT (win), TIC_IN_KEY_DOWN,
-                                          GUINT_TO_POINTER (TRUE));
-       [nsview keyDown: nsevent];
-    }
-  /* JIS_Eisu || JIS_Kana */
-  if (event->hardware_keycode == 102 || event->hardware_keycode == 104)
-    return FALSE;
-
-  retval = output_result(context, win);
-  g_object_set_data (G_OBJECT (win), TIC_IN_KEY_DOWN,
-                                     GUINT_TO_POINTER (FALSE));
-  GTK_NOTE (MISC, g_print ("quartz_filter_keypress done\n"));
-
-  return retval;
-}
-
-static void
-discard_preedit (GtkIMContext *context)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-
-  if (!qc->client_window)
-    return;
-
-  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
-    return;
-
-  NSView *nsview = gdk_quartz_window_get_nsview (qc->client_window);
-  if (!nsview)
-    return;
-
-  /* reset any partial input for this NSView */
-  [(GdkQuartzView *)nsview unmarkText];
-  NSInputManager *currentInputManager = [NSInputManager currentInputManager];
-  [currentInputManager markedTextAbandoned:nsview];
-
-  if (qc->preedit_str && strlen (qc->preedit_str) > 0)
-    {
-      g_signal_emit_by_name (context, "commit", qc->preedit_str);
-
-      g_free (qc->preedit_str);
-      qc->preedit_str = NULL;
-      g_signal_emit_by_name (context, "preedit_changed");
-    }
-}
-
-static void
-quartz_reset (GtkIMContext *context)
-{
-  GTK_NOTE (MISC, g_print ("quartz_reset\n"));
-  discard_preedit (context);
-}
-
-static void
-quartz_set_client_window (GtkIMContext *context, GtkWidget *widget)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-
-  GTK_NOTE (MISC, g_print ("quartz_set_client_window: %p\n", widget));
-
-  qc->client_window = gtk_widget_get_parent_window (widget);
-}
-
-static void
-quartz_focus_in (GtkIMContext *context)
-{
-  GTK_NOTE (MISC, g_print ("quartz_focus_in\n"));
-
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-  qc->focused = TRUE;
-}
-
-static void
-quartz_focus_out (GtkIMContext *context)
-{
-  GTK_NOTE (MISC, g_print ("quartz_focus_out\n"));
-
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-  qc->focused = FALSE;
-
-  /* Commit any partially built strings or it'll mess up other GTK+ widgets in the window */
-  discard_preedit (context);
-}
-
-static void
-quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
-{
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
-  gint x, y;
-  NSView *nsview;
-  GdkWindow *win;
-
-  GTK_NOTE (MISC, g_print ("quartz_set_cursor_location\n"));
-
-  if (!qc->client_window)
-    return;
-
-  if (!qc->focused)
-    return;
-
-  qc->cursor_rect->x = area->x;
-  qc->cursor_rect->y = area->y;
-  qc->cursor_rect->width = area->width;
-  qc->cursor_rect->height = area->height;
-
-  gdk_window_get_origin (qc->client_window, &x, &y);
-
-  qc->cursor_rect->x = area->x + x;
-  qc->cursor_rect->y = area->y + y;
-
-  if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
-    return;
-
-  nsview = gdk_quartz_window_get_nsview (qc->client_window);
-  win = (GdkWindow *)[ (GdkQuartzView*)nsview gdkWindow];
-  g_object_set_data (G_OBJECT (win), GIC_CURSOR_RECT, qc->cursor_rect);
-}
-
-static void
-quartz_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
-{
-  GTK_NOTE (MISC, g_print ("quartz_set_use_preedit: %d\n", use_preedit));
-}
-
-static void
-commit_cb (GtkIMContext *context, const gchar *str, GtkIMContextQuartz *qc)
-{
-  g_signal_emit_by_name (qc, "commit", str);
-}
-
-static void
-imquartz_finalize (GObject *obj)
-{
-  GTK_NOTE (MISC, g_print ("imquartz_finalize\n"));
-
-  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (obj);
-  g_free (qc->preedit_str);
-  qc->preedit_str = NULL;
-  g_free (qc->cursor_rect);
-  qc->cursor_rect = NULL;
-
-  g_signal_handlers_disconnect_by_func (qc->slave, (gpointer)commit_cb, qc);
-  g_object_unref (qc->slave);
-
-  gtk_im_context_quartz_parent_class->finalize (obj);
-}
-
-static void
-gtk_im_context_quartz_class_init (GtkIMContextQuartzClass *class)
-{
-  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_class_init\n"));
-
-  GtkIMContextClass *klass = GTK_IM_CONTEXT_CLASS (class);
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-  klass->get_preedit_string = quartz_get_preedit_string;
-  klass->filter_keypress = quartz_filter_keypress;
-  klass->reset = quartz_reset;
-  klass->set_client_widget = quartz_set_client_window;
-  klass->focus_in = quartz_focus_in;
-  klass->focus_out = quartz_focus_out;
-  klass->set_cursor_location = quartz_set_cursor_location;
-  klass->set_use_preedit = quartz_set_use_preedit;
-
-  object_class->finalize = imquartz_finalize;
-}
-
-static void
-gtk_im_context_quartz_class_finalize (GtkIMContextQuartzClass *class)
-{
-}
-
-static void
-gtk_im_context_quartz_init (GtkIMContextQuartz *qc)
-{
-  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_init\n"));
-
-  qc->preedit_str = g_strdup ("");
-  qc->cursor_index = 0;
-  qc->selected_len = 0;
-  qc->cursor_rect = g_malloc (sizeof (GdkRectangle));
-  qc->focused = FALSE;
-
-  qc->slave = g_object_new (GTK_TYPE_IM_CONTEXT_SIMPLE, NULL);
-  g_signal_connect (G_OBJECT (qc->slave), "commit", G_CALLBACK (commit_cb), qc);
-}
diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c
deleted file mode 100644 (file)
index 24f4f39..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <wayland-client-protocol.h>
-
-#include <gtk/gtk.h>
-#include "gtk/gtkintl.h"
-#include "gtk/gtkimmodule.h"
-
-#include "gdk/wayland/gdkwayland.h"
-#include "gtk-text-input-client-protocol.h"
-
-typedef struct _GtkIMContextWaylandGlobal GtkIMContextWaylandGlobal;
-typedef struct _GtkIMContextWayland GtkIMContextWayland;
-typedef struct _GtkIMContextWaylandClass GtkIMContextWaylandClass;
-
-struct _GtkIMContextWaylandGlobal
-{
-  struct wl_display *display;
-  struct wl_registry *registry;
-  struct gtk_text_input_manager *text_input_manager;
-  struct gtk_text_input *text_input;
-  uint32_t enter_serial;
-
-  GtkIMContext *current;
-};
-
-struct _GtkIMContextWaylandClass
-{
-  GtkIMContextSimpleClass parent_class;
-};
-
-struct _GtkIMContextWayland
-{
-  GtkIMContextSimple parent_instance;
-  GtkWidget *widget;
-
-  GtkGesture *gesture;
-  gdouble press_x;
-  gdouble press_y;
-
-  struct {
-    gchar *text;
-    gint cursor_idx;
-  } surrounding;
-
-  struct {
-    gchar *text;
-    gint cursor_idx;
-  } preedit;
-
-  cairo_rectangle_int_t cursor_rect;
-  guint use_preedit : 1;
-};
-
-static GtkIMContextWaylandGlobal *global = NULL;
-
-static void gtk_im_context_wayland_global_init (GdkDisplay *display);
-
-#define GTK_TYPE_IM_CONTEXT_WAYLAND (gtk_im_context_wayland_get_type ())
-#define GTK_IM_CONTEXT_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT_WAYLAND, GtkIMContextWayland))
-
-G_DEFINE_DYNAMIC_TYPE (GtkIMContextWayland, gtk_im_context_wayland, GTK_TYPE_IM_CONTEXT_SIMPLE)
-
-void
-g_io_module_load (GIOModule *module)
-{
-  g_type_module_use (G_TYPE_MODULE (module));
-
-  g_print ("load io module for wayland\n");
-  gtk_im_context_wayland_register_type (G_TYPE_MODULE (module));
-  gtk_im_context_wayland_global_init (gdk_display_get_default ());
-
-  g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
-                                  GTK_TYPE_IM_CONTEXT_WAYLAND,
-                                  "wayland",
-                                  10);
-}
-
-void
-g_io_module_unload (GIOModule *module)
-{
-}
-
-char **
-g_io_module_query (void)
-{
-  char *eps[] = {
-    GTK_IM_MODULE_EXTENSION_POINT_NAME,
-    NULL
-  };
-
-  return g_strdupv (eps);
-}
-
-
-
-static void
-reset_preedit (GtkIMContextWayland *context)
-{
-  g_clear_pointer (&context->preedit.text, g_free);
-  context->preedit.cursor_idx = 0;
-  g_signal_emit_by_name (context, "preedit-changed");
-}
-
-static void
-text_input_enter (void                     *data,
-                  struct gtk_text_input    *text_input,
-                  uint32_t                  serial,
-                  struct wl_surface        *surface)
-{
-  GtkIMContextWaylandGlobal *global = data;
-
-  global->enter_serial = serial;
-}
-
-static void
-text_input_leave (void                     *data,
-                  struct gtk_text_input    *text_input,
-                  uint32_t                  serial,
-                  struct wl_surface        *surface)
-{
-  GtkIMContextWayland *context;
-
-  if (!global->current)
-    return;
-
-  context = GTK_IM_CONTEXT_WAYLAND (global->current);
-  reset_preedit (context);
-}
-
-static void
-text_input_preedit (void                     *data,
-                    struct gtk_text_input    *text_input,
-                    const char               *text,
-                    guint                     cursor)
-{
-  GtkIMContextWayland *context;
-  gboolean state_change;
-
-  if (!global->current)
-    return;
-
-  context = GTK_IM_CONTEXT_WAYLAND (global->current);
-  if (!text && !context->preedit.text)
-    return;
-
-  state_change = ((text == NULL) != (context->preedit.text == NULL));
-
-  if (state_change && !context->preedit.text)
-    g_signal_emit_by_name (context, "preedit-start");
-
-  g_free (context->preedit.text);
-  context->preedit.text = g_strdup (text);
-  context->preedit.cursor_idx = cursor;
-
-  g_signal_emit_by_name (context, "preedit-changed");
-
-  if (state_change && !context->preedit.text)
-    g_signal_emit_by_name (context, "preedit-end");
-}
-
-static void
-text_input_commit (void                     *data,
-                   struct gtk_text_input    *text_input,
-                   const char               *text)
-{
-  GtkIMContextWaylandGlobal *global = data;
-
-  if (global->current && text)
-    g_signal_emit_by_name (global->current, "commit", text);
-}
-
-static void
-text_input_delete_surrounding_text (void                     *data,
-                                    struct gtk_text_input    *text_input,
-                                    uint32_t                  offset,
-                                    uint32_t                  len)
-{
-  GtkIMContextWaylandGlobal *global = data;
-
-  if (global->current)
-    g_signal_emit_by_name (global->current, "delete-surrounding", offset, len);
-}
-
-static const struct gtk_text_input_listener text_input_listener = {
-  text_input_enter,
-  text_input_leave,
-  text_input_preedit,
-  text_input_commit,
-  text_input_delete_surrounding_text
-};
-
-static void
-registry_handle_global (void               *data,
-                        struct wl_registry *registry,
-                        uint32_t            id,
-                        const char         *interface,
-                        uint32_t            version)
-{
-  GtkIMContextWaylandGlobal *global = data;
-  GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
-
-  if (strcmp (interface, "gtk_text_input_manager") == 0)
-    {
-      global->text_input_manager =
-        wl_registry_bind (global->registry, id,
-                          &gtk_text_input_manager_interface, 1);
-      global->text_input =
-        gtk_text_input_manager_get_text_input (global->text_input_manager,
-                                               gdk_wayland_seat_get_wl_seat (seat));
-      gtk_text_input_add_listener (global->text_input,
-                                   &text_input_listener, global);
-    }
-}
-
-static void
-registry_handle_global_remove (void               *data,
-                               struct wl_registry *registry,
-                               uint32_t            id)
-{
-  GtkIMContextWaylandGlobal *global = data;
-
-  gtk_text_input_destroy (global->text_input);
-  global->text_input = NULL;
-
-  gtk_text_input_manager_destroy (global->text_input_manager);
-  global->text_input_manager = NULL;
-}
-
-static const struct wl_registry_listener registry_listener = {
-    registry_handle_global,
-    registry_handle_global_remove
-};
-
-static void
-gtk_im_context_wayland_global_init (GdkDisplay *display)
-{
-  if (global)
-    return;
-
-  global = g_new0 (GtkIMContextWaylandGlobal, 1);
-  global->display = gdk_wayland_display_get_wl_display (display);
-  global->registry = wl_display_get_registry (global->display);
-
-  wl_registry_add_listener (global->registry, &registry_listener, global);
-}
-
-static void
-notify_surrounding_text (GtkIMContextWayland *context)
-{
-  if (!global || !global->text_input)
-    return;
-  if (global->current != GTK_IM_CONTEXT (context))
-    return;
-  if (!context->surrounding.text)
-    return;
-
-  gtk_text_input_set_surrounding_text (global->text_input,
-                                       context->surrounding.text,
-                                       context->surrounding.cursor_idx,
-                                       context->surrounding.cursor_idx);
-}
-
-static void
-notify_cursor_location (GtkIMContextWayland *context)
-{
-  cairo_rectangle_int_t rect;
-
-  if (!global || !global->text_input)
-    return;
-  if (global->current != GTK_IM_CONTEXT (context))
-    return;
-  if (!context->widget)
-    return;
-
-  rect = context->cursor_rect;
-  gtk_widget_translate_coordinates (context->widget,
-                                    gtk_widget_get_toplevel (context->widget),
-                                    rect.x, rect.y,
-                                    &rect.x, &rect.y);
-
-  gtk_text_input_set_cursor_rectangle (global->text_input,
-                                       rect.x, rect.y,
-                                       rect.width, rect.height);
-}
-
-static uint32_t
-translate_hints (GtkInputHints   input_hints,
-                 GtkInputPurpose purpose)
-{
-  uint32_t hints = 0;
-
-  if (input_hints & GTK_INPUT_HINT_SPELLCHECK)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_SPELLCHECK;
-  if (input_hints & GTK_INPUT_HINT_WORD_COMPLETION)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_COMPLETION;
-  if (input_hints & GTK_INPUT_HINT_LOWERCASE)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
-  if (input_hints & GTK_INPUT_HINT_UPPERCASE_CHARS)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
-  if (input_hints & GTK_INPUT_HINT_UPPERCASE_WORDS)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_TITLECASE;
-  if (input_hints & GTK_INPUT_HINT_UPPERCASE_SENTENCES)
-    hints |= GTK_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
-
-  if (purpose == GTK_INPUT_PURPOSE_PIN ||
-      purpose == GTK_INPUT_PURPOSE_PASSWORD)
-    {
-      hints |= (GTK_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT |
-                GTK_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA);
-    }
-
-  return hints;
-}
-
-static uint32_t
-translate_purpose (GtkInputPurpose purpose)
-{
-  switch (purpose)
-    {
-    case GTK_INPUT_PURPOSE_FREE_FORM:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
-    case GTK_INPUT_PURPOSE_ALPHA:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_ALPHA;
-    case GTK_INPUT_PURPOSE_DIGITS:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
-    case GTK_INPUT_PURPOSE_NUMBER:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
-    case GTK_INPUT_PURPOSE_PHONE:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
-    case GTK_INPUT_PURPOSE_URL:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_URL;
-    case GTK_INPUT_PURPOSE_EMAIL:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
-    case GTK_INPUT_PURPOSE_NAME:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_NAME;
-    case GTK_INPUT_PURPOSE_PASSWORD:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
-    case GTK_INPUT_PURPOSE_PIN:
-      return GTK_TEXT_INPUT_CONTENT_PURPOSE_PIN;
-    }
-
-  return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
-}
-
-static void
-notify_content_type (GtkIMContextWayland *context)
-{
-  GtkInputHints hints;
-  GtkInputPurpose purpose;
-
-  if (global->current != GTK_IM_CONTEXT (context))
-    return;
-
-  g_object_get (context,
-                "input-hints", &hints,
-                "input-purpose", &purpose,
-                NULL);
-
-  gtk_text_input_set_content_type (global->text_input,
-                                   translate_hints (hints, purpose),
-                                   translate_purpose (purpose));
-}
-
-static void
-commit_state (GtkIMContextWayland *context)
-{
-  if (global->current != GTK_IM_CONTEXT (context))
-    return;
-  gtk_text_input_commit (global->text_input);
-}
-
-static void
-enable_text_input (GtkIMContextWayland *context,
-                   gboolean             toggle_panel)
-{
-  guint flags = 0;
-
-  if (context->use_preedit)
-    flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_CAN_SHOW_PREEDIT;
-  if (toggle_panel)
-    flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_TOGGLE_INPUT_PANEL;
-
-  gtk_text_input_enable (global->text_input,
-                         global->enter_serial,
-                         flags);
-}
-
-static void
-gtk_im_context_wayland_finalize (GObject *object)
-{
-  GtkIMContextWayland *context = GTK_IM_CONTEXT_WAYLAND (object);
-
-  g_clear_object (&context->widget);
-  g_clear_object (&context->gesture);
-
-  G_OBJECT_CLASS (gtk_im_context_wayland_parent_class)->finalize (object);
-}
-
-static void
-pressed_cb (GtkGestureMultiPress *gesture,
-            gint                  n_press,
-            gdouble               x,
-            gdouble               y,
-            GtkIMContextWayland  *context)
-{
-  if (n_press == 1)
-    {
-      context->press_x = x;
-      context->press_y = y;
-    }
-}
-
-static void
-released_cb (GtkGestureMultiPress *gesture,
-             gint                  n_press,
-             gdouble               x,
-             gdouble               y,
-             GtkIMContextWayland  *context)
-{
-  GtkInputHints hints;
-
-  g_object_get (context, "input-hints", &hints, NULL);
-
-  if (n_press == 1 &&
-      (hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
-      !gtk_drag_check_threshold (context->widget,
-                                 context->press_x,
-                                 context->press_y,
-                                 x, y))
-    {
-      enable_text_input (GTK_IM_CONTEXT_WAYLAND (context), TRUE);
-    }
-}
-
-static void
-gtk_im_context_wayland_set_client_widget (GtkIMContext *context,
-                                          GtkWidget    *widget)
-{
-  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  if (widget == context_wayland->widget)
-    return;
-
-  if (context_wayland->widget && context_wayland->widget != widget)
-    g_clear_object (&context_wayland->gesture);
-
-  g_set_object (&context_wayland->widget, widget);
-
-  if (widget)
-    {
-      GtkGesture *gesture;
-
-      gesture = gtk_gesture_multi_press_new (widget);
-      gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
-                                                  GTK_PHASE_CAPTURE);
-      g_signal_connect (gesture, "pressed",
-                        G_CALLBACK (pressed_cb), context);
-      g_signal_connect (gesture, "released",
-                        G_CALLBACK (released_cb), context);
-      context_wayland->gesture = gesture;
-    }
-}
-
-static void
-gtk_im_context_wayland_get_preedit_string (GtkIMContext   *context,
-                                           gchar         **str,
-                                           PangoAttrList **attrs,
-                                           gint           *cursor_pos)
-{
-  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-  gchar *preedit_str;
-
-  GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->get_preedit_string (context, str, attrs, cursor_pos);
-
-  /* If the parent implementation returns a len>0 string, go with it */
-  if (str && *str && **str)
-    return;
-
-  preedit_str =
-    context_wayland->preedit.text ? context_wayland->preedit.text : "";
-
-  if (str)
-    *str = g_strdup (preedit_str);
-  if (cursor_pos)
-    *cursor_pos = context_wayland->preedit.cursor_idx;
-
-  if (attrs)
-    {
-      *attrs = pango_attr_list_new ();
-      pango_attr_list_insert (*attrs,
-                              pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
-    }
-}
-
-static gboolean
-gtk_im_context_wayland_filter_keypress (GtkIMContext *context,
-                                        GdkEventKey  *key)
-{
-  /* This is done by the compositor */
-  return GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->filter_keypress (context, key);
-}
-
-static void
-gtk_im_context_wayland_focus_in (GtkIMContext *context)
-{
-  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  if (global->current == context)
-    return;
-  if (!global->text_input)
-    return;
-
-  global->current = context;
-  enable_text_input (context_wayland, FALSE);
-  notify_content_type (context_wayland);
-  notify_surrounding_text (context_wayland);
-  notify_cursor_location (context_wayland);
-  commit_state (context_wayland);
-}
-
-static void
-gtk_im_context_wayland_focus_out (GtkIMContext *context)
-{
-  if (global->current != context)
-    return;
-
-  gtk_text_input_disable (global->text_input);
-  global->current = NULL;
-}
-
-static void
-gtk_im_context_wayland_reset (GtkIMContext *context)
-{
-  reset_preedit (GTK_IM_CONTEXT_WAYLAND (context));
-
-  GTK_IM_CONTEXT_CLASS (gtk_im_context_wayland_parent_class)->reset (context);
-}
-
-static void
-gtk_im_context_wayland_set_cursor_location (GtkIMContext *context,
-                                            GdkRectangle *rect)
-{
-  GtkIMContextWayland *context_wayland;
-
-  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  context_wayland->cursor_rect = *rect;
-  notify_cursor_location (context_wayland);
-  commit_state (context_wayland);
-}
-
-static void
-gtk_im_context_wayland_set_use_preedit (GtkIMContext *context,
-                                        gboolean      use_preedit)
-{
-  GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  context_wayland->use_preedit = !!use_preedit;
-}
-
-static void
-gtk_im_context_wayland_set_surrounding (GtkIMContext *context,
-                                        const gchar  *text,
-                                        gint          len,
-                                        gint          cursor_index)
-{
-  GtkIMContextWayland *context_wayland;
-
-  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  g_free (context_wayland->surrounding.text);
-  context_wayland->surrounding.text = g_strdup (text);
-  context_wayland->surrounding.cursor_idx = cursor_index;
-
-  notify_surrounding_text (context_wayland);
-  commit_state (context_wayland);
-}
-
-static gboolean
-gtk_im_context_wayland_get_surrounding (GtkIMContext  *context,
-                                        gchar        **text,
-                                        gint          *cursor_index)
-{
-  GtkIMContextWayland *context_wayland;
-
-  context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
-
-  if (!context_wayland->surrounding.text)
-    return FALSE;
-
-  *text = context_wayland->surrounding.text;
-  *cursor_index = context_wayland->surrounding.cursor_idx;
-  return TRUE;
-}
-
-static void
-gtk_im_context_wayland_class_init (GtkIMContextWaylandClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass);
-
-  object_class->finalize = gtk_im_context_wayland_finalize;
-
-  im_context_class->set_client_widget = gtk_im_context_wayland_set_client_widget;
-  im_context_class->get_preedit_string = gtk_im_context_wayland_get_preedit_string;
-  im_context_class->filter_keypress = gtk_im_context_wayland_filter_keypress;
-  im_context_class->focus_in = gtk_im_context_wayland_focus_in;
-  im_context_class->focus_out = gtk_im_context_wayland_focus_out;
-  im_context_class->reset = gtk_im_context_wayland_reset;
-  im_context_class->set_cursor_location = gtk_im_context_wayland_set_cursor_location;
-  im_context_class->set_use_preedit = gtk_im_context_wayland_set_use_preedit;
-  im_context_class->set_surrounding = gtk_im_context_wayland_set_surrounding;
-  im_context_class->get_surrounding = gtk_im_context_wayland_get_surrounding;
-}
-
-static void
-gtk_im_context_wayland_class_finalize (GtkIMContextWaylandClass *class)
-{
-}
-
-static void
-on_content_type_changed (GtkIMContextWayland *context)
-{
-  notify_content_type (context);
-  commit_state (context);
-}
-
-static void
-gtk_im_context_wayland_init (GtkIMContextWayland *context)
-{
-  context->use_preedit = TRUE;
-  g_signal_connect_swapped (context, "notify::input-purpose",
-                            G_CALLBACK (on_content_type_changed), context);
-  g_signal_connect_swapped (context, "notify::input-hints",
-                            G_CALLBACK (on_content_type_changed), context);
-}
diff --git a/modules/input/meson.build b/modules/input/meson.build
deleted file mode 100644 (file)
index ae904b8..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-# Note: this file is included from the top-level before gtk/meson.build.
-# The actual input modules are then built in gtk/meson.build based on the
-# defs we provide here. It has to be that way because included input methods
-# need to be built before libgtk-4.so is built, so before gtk/meson.build, but
-# all input methods also rely on gtk generated headers to be created first, so
-# there is a bit of an ordering problem which we solve by collecting all the
-# information here but moving the actual build definitions to gtk/meson.build.
-build_dynamic_modules = false
-dynamic_modules = get_option('dynamic-modules')
-if dynamic_modules
-  gmodule_supported = dependency('gmodule-no-export-2.0').get_pkgconfig_variable('gmodule_supported')
-  if gmodule_supported == 'true'
-    build_dynamic_modules = true
-  else
-    message('Modules are not supported according to gmodule-no-export-2.0.pc')
-  endif
-endif
-
-all_immodules = backend_immodules
-
-# Allow building some or all immodules included
-included_immodules = get_option('included-immodules').split(',')
-if included_immodules.contains('none')
-  included_immodules = []
-elif included_immodules.contains('all')
-  included_immodules = all_immodules
-endif
-
-have_included_immodules = included_immodules.length() > 0
-
-foreach im: included_immodules
-  if not all_immodules.contains(im)
-    error('The specified input method "@0@" is not available (available methods: @1@)'.format(im, ', '.join(all_immodules)))
-  endif
-endforeach
-
-immodules_subdir = 'gtk-4.0/@0@/immodules'.format(gtk_binary_version)
-immodules_install_dir = join_paths(gtk_libdir, immodules_subdir)
-
-# Format:
-#  - protocol name
-#  - protocol stability ('stable' or 'unstable')
-#  - protocol version (if stability is 'unstable')
-proto_sources = [
-  ['gtk-text-input', 'stable', ],
-]
-
-im_wayland_gen_headers = []
-im_wayland_sources = files('imwayland.c')
-wayland_scanner = find_program('wayland-scanner')
-genprotocols = find_program('../../gdk/wayland/genprotocolfiles.py')
-
-foreach p: proto_sources
-  proto_name = p.get(0)
-  proto_stability = p.get(1)
-
-  if proto_stability == 'stable'
-    output_base = proto_name
-    input = '@0@.xml'.format(proto_name)
-  else
-    proto_version = p.get(2)
-    output_base = '@0@-@1@-@2@'.format(proto_name, proto_stability, proto_version)
-    input = join_paths(proto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
-  endif
-
-  im_wayland_sources += custom_target('@0@ client header'.format(output_base),
-                                      input: input,
-                                      output: '@0@-client-protocol.h'.format(output_base),
-                                      command: [
-                                        genprotocols,
-                                        wayland_scanner,
-                                        '@INPUT@', '@OUTPUT@',
-                                        'client-header',
-                                      ])
-
-  im_wayland_sources += custom_target('@0@ source'.format(output_base),
-                                      input: input,
-                                      output: '@0@-protocol.c'.format(output_base),
-                                      command: [
-                                        genprotocols,
-                                        wayland_scanner,
-                                        '@INPUT@', '@OUTPUT@',
-                                        'code',
-                                      ])
-endforeach
-
-method_defs = [
-  ['broadway', files('imbroadway.c')],
-  ['quartz', ('imquartz.c'), [], ('-xobjective-c')],
-  ['xim', files('gtkimcontextxim.c')],
-  ['ime', files('gtkimcontextime.c'), ['imm32']],
-  ['wayland', im_wayland_sources],
-]
-
-inc_im_method_defs = []
-dyn_im_method_defs = []
-
-foreach m: method_defs
-  im = m.get(0)
-  srcs = m.get(1)
-  cargs = m.get(3, [])
-  libs = []
-
-  # only use backend-specific input methods for backends that are enabled
-  if all_immodules.contains(im)
-    # check for extra libs lazily
-    foreach libname: m.get(2, [])
-      libs += [cc.find_library(libname)]
-    endforeach
-
-    if included_immodules.contains(im)
-      cdata.set('INCLUDE_IM_@0@'.format(im.underscorify()), true)
-      inc_im_method_defs += [[im, srcs, cargs, libs]]
-    elif build_dynamic_modules
-      dyn_im_method_defs += [[im, srcs, cargs, libs]]
-    endif
-  endif
-endforeach
index d0c4adc81d4269dfc9caf21460e7a3654ce375a3..cde966a094d05d84b91d9884a28b0bd1c2d6bf87 100644 (file)
@@ -1,5 +1,3 @@
-# Note: 'input' subdir has already been included from top-level.
-
 if os_unix
   subdir('printbackends')
 endif